# Security posture
## What this plugin does and does not do
- **No network access.** The plugin never opens a socket. It reads local git
repositories and runs a coding-agent CLI that the user has already installed
and authenticated. Any network traffic is that agent's own.
- **No writes outside its own state.** It writes only to
`~/.local/share/omarchy-standup/` (created mode `700`) and to its own widget
entry in `~/.config/omarchy/shell.json`. It never writes inside the scanned
repositories; every git command it runs is a read (`log`, `rev-parse`,
`config --local user.email`).
- **No privileged operations.** No sudo, no systemd units, no polkit, no
filesystem mounts, no symlinks in the package.
## Untrusted input and where it goes
Commit subjects, author names, branch names and directory names come from
whatever repositories are on disk — including ones the user only cloned. They
are treated as data everywhere:
| Sink | Handling |
| --- | --- |
| JSON output | Built with `jq --arg` / `--argjson` and `python3 json.dump`; never string-concatenated |
| Shell | No `eval`, no `sh -c`, no backticks. Every external call is argv (`git -C
log ...`) |
| The agent prompt | Passed as inert text, on stdin where the CLI supports it |
| The panel | Every `Text` element sets `textFormat: Text.PlainText`, so no HTML or rich-text parsing happens and nothing can trigger a remote fetch |
| Clipboard | `Quickshell.execDetached(["wl-copy", "--", text])` — argv, with `--` terminating options |
## Prompt injection
A hostile commit message can address the model directly. The mitigation is to
give the model nothing to act with: the agent runs with tools disabled where
its CLI offers the switch (`claude --tools ""`, `codex exec --sandbox
read-only`, `gemini --approval-mode plan`) and always with its working
directory set to an empty scratch folder, away from the user's projects and
any rules files in them. Agents without such a switch run with their own
defaults, which the README states plainly.
The worst case that remains is a misleading standup — the model repeating text
a commit message told it to. Nothing in the pipeline executes the result; it is
written to a file and drawn as plain text.
## Resource bounds
Every stream that could be attacker-influenced is capped, so no input can
exhaust memory:
| Stream | Cap |
| --- | --- |
| `git log` output per repository | 200 KB |
| Commits per repository / per run | 40 / 300 |
| Commit subject | 120 characters |
| Author scan across all repos | 4 MB |
| Agent reply | 64 KB |
| Rendered lines | 40 |
| Stored standups | 60, older files pruned |
The agent call has a 240-second timeout, and generation takes a `flock` so two
runs cannot interleave.
## Path handling
Entry ids are unix timestamps and end up in a file path, so `show`, `delete`
and `seen` refuse anything that is not `^[0-9]+$` rather than trying to sanitise
it. Only a leading `~` is expanded in configured paths. `find` is not given
`-L`, so symlinked directories are not followed out of the scan roots.
## The custom command setting
Choosing **Custom command** lets the user name any executable to write the
standup. It is split into argv words and executed directly — never through a
shell — so shell metacharacters in that setting are inert argument text rather
than commands. It receives the prompt on stdin and nothing else. This is the
user configuring their own machine, and it is the feature that makes a local
model possible.
## Reporting
Open an issue at https://github.com/Bottelet/omarchy-standup/issues.