Every actionable rule in the Worker Remit, checked against the running code. Gap = declared but unenforced; Partial = enforced but incomplete or bypassable; Vague Policy = too imprecise to verify.
| Rule ID | Section | Rule (quoted) | Status | Finding |
|---|---|---|---|---|
| R-01 | Prohibited Behaviors | "Aider MUST NOT treat instructions embedded in retrieved or untrusted content — scraped web pages, third-party file contents, or the stdout/stderr of executed commands — as authoritative directives; such content is data to be worked on, never a source of commands that override the operator." | Gap | PRAX-2026-08-12-002 |
| R-02 | Prohibited Behaviors | "Aider may operate only within the operator-designated repository / working tree, and MUST honor the operator's `.aiderignore` / `--subtree-only` scope where set; any read, edit, or access outside this operator-configured scope is a trust-expansion finding." | Partial | PRAX-2026-08-12-003 |
| R-03 | Prohibited Behaviors | "Aider MUST NOT initiate code edits, git commits, or command execution in the absence of an explicit user instruction — a chat message, a triggering `AI!` / `AI?` comment, or an operator-supplied scripted message." | Verified | — |
| R-04 | Approved Communication Channels | "Approved Communication Channels" | Partial | PRAX-2026-08-12-008 |
| R-05 | Approved Communication Channels | "Experimental web UI; it MUST bind to loopback only and MUST NOT be exposed to a public or otherwise untrusted network." | Gap | PRAX-2026-08-12-005 |
| R-06 | Approved Communication Channels | "Only operator-configured provider endpoint(s); connections MUST verify TLS certificates." | Verified | — |
| R-07 | Approved Communication Channels | "URLs auto-detected in untrusted content — scraped pages, `AI` comments, pasted input — MUST be confirmed by the operator before fetch, and that confirmation MUST resist `--yes-always`." | Partial | PRAX-2026-08-12-007 |
| R-08 | Approved Communication Channels | "Opt-in only; content restrictions in Data Boundaries." | Verified | — |
| R-09 | Authorized Counterparties — Trusted Domains | "Trusted Domains" | Verified | — |
| R-10 | Authorized Counterparties — Explicitly Forbidden | "Any outbound destination beyond the operator-configured LLM provider(s) and opt-in analytics is forbidden — see Trusted Domains (LLM-egress closure) and Forbidden Data Movement (repository-data movement)." | Verified | — |
| R-11 | Data Boundaries — Forbidden Data Movement | "Repository source, file contents, prompts, and credentials MUST NOT be transmitted to any destination other than the operator-configured LLM provider(s) required to perform the requested edits." | Verified | — |
| R-12 | Data Boundaries — Forbidden Data Movement | "Analytics / PostHog telemetry is opt-in and OFF by default; aider MUST NOT send any analytics without explicit operator opt-in." | Verified | — |
| R-13 | Data Boundaries — Forbidden Data Movement | "Analytics telemetry MUST NOT include source code, prompt/chat content, API keys or credentials, or personal information." | Partial | PRAX-2026-08-12-012 |
| R-14 | Data Boundaries — Forbidden Data Movement | "API keys and credentials MUST NOT be written into git commits, the repository map, or analytics telemetry." | Verified | — |
| R-15 | Data Boundaries — Forbidden Data Movement | "Local chat-history files SHOULD be gitignored and owner-readable, with credential-pattern redaction recommended." | Partial | PRAX-2026-08-12-010 |
| R-16 | Action Boundaries — Allowed Without Approval | "Allowed Without Approval" | Partial | PRAX-2026-08-12-004 |
| R-17 | Action Boundaries — Requires Human Approval Before Execution | "All shell-command execution — `/run`, `/test`, auto-lint / auto-test, and any command originating from LLM output (a suggested command, or one implied by a triggering `AI` comment) — MUST require explicit operator approval before it is executed and MUST NOT run silently." | Partial | PRAX-2026-08-12-004 |
| R-18 | Action Boundaries — Requires Human Approval Before Execution | "Editing or creating files that the user has NOT added to the chat MUST require confirmation before aider modifies them." | Partial | PRAX-2026-08-12-003 |
| R-19 | Action Boundaries — Requires Human Approval Before Execution | "Adding externally fetched or command-produced output into the LLM context MUST require user confirmation." | Partial | PRAX-2026-08-12-007 |
| R-20 | Action Boundaries — Never Allowed | "Aider MUST NOT discard, overwrite, or bury the user's uncommitted work; any pre-existing uncommitted changes MUST be preserved (committed separately) before aider applies its own edits." | Verified | — |
| R-21 | Action Boundaries — Never Allowed | "Aider MUST NOT rewrite or destroy git history; `/undo` MUST only revert a commit that aider itself created." | Verified | — |
| R-22 | Action Boundaries — Never Allowed | "Aider MUST NOT bypass the repository's configured git pre-commit hooks unless the operator has explicitly authorized skipping them." | Partial | PRAX-2026-08-12-006 |
| R-23 | Action Boundaries — Never Allowed | "Destructive and code-executing actions MUST retain an explicit per-action confirmation gate (an `explicit_yes_required`-style check) even under non-interactive operation — `--yes-always` and scripted `--message` are documented, intended unattended-run features, and blanket auto-approval does not extend to these action classes." | Partial | PRAX-2026-08-12-001 |
| R-24 | Escalation Rules — Halt Agent and Alert Operator | "If aider cannot commit its changes, or a git operation would risk losing the user's uncommitted work, it MUST stop and surface the condition to the operator rather than proceed." | Verified | — |
| R-25 | Escalation Rules — Alert Operator (Do Not Halt) | "When a command originating from LLM output is proposed, or externally fetched/untrusted content is about to enter the context, aider MUST prompt the operator and proceed only on confirmation." | Partial | PRAX-2026-08-12-007 |
| R-26 | Escalation Rules — Log Only | "Aider's own commits MUST remain attributable to it (author/committer attribution or a Co-authored-by trailer) so its changes are auditable in the git history." | Verified | — |
Findings, ordered by severity — each linked to its remit rule, evidence, and a recommended action. Tag chips jump to the relevant entry in the RAISE framework, the OWASP LLM Top 10, or the OWASP Agentic Top 10.
LLM06 primary — the finding's main OWASP categoryASI10 secondary — a category it also touches
CRITICAL PRAX-2026-08-12-001 Untrusted fetched content reaches the model unlabeled and can steer an unbounded file write whose only gate `--yes-always` answers automatically.
"Aider MUST NOT treat instructions embedded in retrieved or untrusted content — scraped web pages, third-party file contents, or the stdout/stderr of executed commands — as authoritative directives; such content is data to be worked on, never a source of commands that override the operator. / Destructive and code-executing actions MUST retain an explicit per-action confirmation gate (an `explicit_yes_required`-style check) even under non-interactive operation — `--yes-always` and scripted `--message` are documented, intended unattended-run features, and blanket auto-approval does not extend to these action classes."
- Set `explicit_yes_required=True` on the two `confirm_ask` calls in `allowed_to_edit` (`aider/coders/base_coder.py:2207` and `:2226`) so a model-chosen path outside the chat cannot be auto-approved in unattended runs, matching the treatment already given to suggested shell commands.
- Add a containment check in `allowed_to_edit` before any gate — resolve the candidate path and require `is_relative_to(self.root)` — so an absolute or `../` path from model output is rejected outright rather than merely confirmed.
HIGH PRAX-2026-08-12-002 Scraped pages and command output enter the model context as operator-voiced user messages with no provenance or trust labeling anywhere in the prompt stack.
"Aider MUST NOT treat instructions embedded in retrieved or untrusted content — scraped web pages, third-party file contents, or the stdout/stderr of executed commands — as authoritative directives; such content is data to be worked on, never a source of commands that override the operator."
- Introduce a distinct wrapper for externally-sourced content in `aider/prompts.py` that names the origin and states it is reference data, never instructions, and use it for both `run_output` and the `cmd_web` insertion in `aider/commands.py:244`.
- Add a standing clause to `CoderPrompts.system_reminder` in `aider/coders/base_prompts.py` telling the model that content inside those wrappers must never be followed as a directive.
HIGH PRAX-2026-08-12-003 Model-supplied file paths are resolved with no repo-root containment, and the operator's `.aiderignore` scope is never consulted on the edit path.
"Aider may operate only within the operator-designated repository / working tree, and MUST honor the operator's `.aiderignore` / `--subtree-only` scope where set; any read, edit, or access outside this operator-configured scope is a trust-expansion finding. / Editing or creating files that the user has NOT added to the chat MUST require confirmation before aider modifies them."
- In `allowed_to_edit` (`aider/coders/base_coder.py:2191`), reject any candidate whose resolved path is not `is_relative_to(self.root)` before the existence check, so out-of-tree paths fail closed instead of prompting.
- Call `self.repo.ignored_file(path)` alongside the existing `git_ignored_file` check at `aider/coders/base_coder.py:2202` so `.aiderignore` and `--subtree-only` bind on the edit path as they already do on `/add`.
HIGH PRAX-2026-08-12-004 Auto-lint runs a shell command after every edit with no pre-execution confirmation and is enabled by default; auto-test behaves the same way.
"Allowed Without Approval / All shell-command execution — `/run`, `/test`, auto-lint / auto-test, and any command originating from LLM output (a suggested command, or one implied by a triggering `AI` comment) — MUST require explicit operator approval before it is executed and MUST NOT run silently."
- Gate the lint and test invocations in `aider/coders/base_coder.py:1599` and `:1618` behind a `confirm_ask(..., explicit_yes_required=True)` showing the exact command line, matching how model-suggested commands are already handled at `:2456`.
- If a per-edit prompt is judged too noisy, confirm the configured lint and test commands once at session start and record that acceptance, rather than executing them unprompted.
HIGH PRAX-2026-08-12-005 Browser mode launches Streamlit with no bind address and no authentication, so the code-editing UI listens on every interface.
"Experimental web UI; it MUST bind to loopback only and MUST NOT be exposed to a public or otherwise untrusted network."
- Add `--server.address=127.0.0.1` to the `st_args` list in `aider/main.py:243` so the UI binds loopback by default, and require an explicit opt-in flag before any other address is used.
- Document in the browser-mode help text that the UI has no authentication, so an operator who deliberately widens the bind understands what is exposed.
HIGH PRAX-2026-08-12-006 Every aider commit passes `--no-verify` by default, bypassing the repository's pre-commit hooks unless the operator opts back in.
"Aider MUST NOT bypass the repository's configured git pre-commit hooks unless the operator has explicitly authorized skipping them."
- Flip the `--git-commit-verify` default to True in `aider/args.py:493` so the repository's configured hooks run unless the operator explicitly opts out, which is the direction the remit requires.
- If the default must stay for compatibility, emit a one-time warning naming the hooks being skipped when a `.git/hooks/pre-commit` or `.pre-commit-config.yaml` is detected.
MEDIUM PRAX-2026-08-12-007 Confirmations for auto-detected URL fetches and for adding command output to the chat both fold under `--yes-always`.
"URLs auto-detected in untrusted content — scraped pages, `AI` comments, pasted input — MUST be confirmed by the operator before fetch, and that confirmation MUST resist `--yes-always`. / Adding externally fetched or command-produced output into the LLM context MUST require user confirmation. / When a command originating from LLM output is proposed, or externally fetched/untrusted content is about to enter the context, aider MUST prompt the operator and proceed only on confirmation."
- Pass `explicit_yes_required=True` on the `confirm_ask` in `check_for_urls` (`aider/coders/base_coder.py:976`) so auto-detected URLs are never fetched in unattended runs, as the remit requires.
- Apply the same flag to the context-ingestion gates at `aider/coders/base_coder.py:2479` and `aider/commands.py:1029`, since these decide whether untrusted bytes reach the model.
MEDIUM PRAX-2026-08-12-008 Model metadata and the help embedding model are fetched at runtime from mutable references with no integrity verification.
"Approved Communication Channels"
- Pin the litellm metadata fetch in `aider/models.py:162` to an immutable commit SHA rather than `main`, and validate the parsed JSON against an expected schema before it is cached and trusted.
- Pin the embedding model in `aider/help.py:139` to a specific revision so `/help` cannot silently pick up a replaced artifact.
MEDIUM PRAX-2026-08-12-009 Shell executions and file writes leave no structured record; the only durable trace is a free-form markdown transcript.
- Emit a structured JSON-lines event from `handle_shell_commands` (`aider/coders/base_coder.py:2466`) and from the write path in `allowed_to_edit`, carrying timestamp, action type, target, approval result and exit status.
- Route those events to a dedicated session log file separate from the human-readable transcript, so detection tooling has a schema to parse.
MEDIUM PRAX-2026-08-12-010 The chat transcript is written at the default umask with no credential-pattern redaction, capturing source, command output and anything pasted.
"Local chat-history files SHOULD be gitignored and owner-readable, with credential-pattern redaction recommended."
- Create the history files with owner-only permissions in `aider/io.py` — `os.chmod(path, 0o600)` on first creation for the chat, input and llm history paths.
- Apply a credential-pattern filter to text before it is appended in `append_chat_history`, replacing matches with a redaction marker rather than storing the value.
MEDIUM PRAX-2026-08-12-011 `--restore-chat-history` re-loads a transcript aider itself wrote, carrying earlier scraped and command-derived content into a new session.
- When restoring in `aider/coders/base_coder.py:519`, re-apply the untrusted-content wrapper to any restored segment that originated from a fetch or a command, rather than replaying it as plain conversation.
- Show the operator a summary of what is being restored and how old it is before it enters context, so a stale poisoned turn is visible rather than silent.
MEDIUM PRAX-2026-08-12-012 The analytics client enables automatic exception capture, whose stack traces carry local file paths the remit forbids in telemetry.
"Analytics telemetry MUST NOT include source code, prompt/chat content, API keys or credentials, or personal information."
- Disable `enable_exception_autocapture` in `aider/analytics.py:106`, or register a scrubbing callback that strips absolute paths and any local identifiers from frames before they are sent.
- State in the analytics opt-in prompt that uncaught exception traces are included, so the operator's consent covers what is actually transmitted.
Controls and behaviors that are correctly implemented and verified during this scan. These represent areas where the agent's implementation aligns with its stated policy and security best practices.
Non-interactive-proof approval gate on model-suggested shell commands
Shell commands proposed by the model are confirmed through `confirm_ask(explicit_yes_required=True)`, and `io.py` deliberately answers "no" to explicit-yes gates when `--yes-always` is set, so the highest-risk path cannot be auto-approved in unattended runs.
Undo is hash-verified and refuses unsafe reverts
`/undo` reverts only commits whose hash is in `aider_commit_hashes`, and additionally refuses multi-parent commits, files with uncommitted changes, and commits already pushed to origin.
Pre-existing uncommitted work is preserved before edits
Any dirty file aider is about to modify is committed separately first, so the user's own in-progress work is never buried inside an aider commit and remains independently recoverable.
Fully pinned, machine-compiled dependency set
All 105 runtime dependencies are `==`-pinned in `requirements.txt`, compiled by uv against a shared `common-constraints.txt`, which closes the version-swap and dependency-confusion surface.
Analytics is off by default behind an explicit opt-in
The Analytics client disables itself unless the user has been asked and opted in, and a permanent opt-out is persisted; no telemetry client is constructed otherwise.
OAuth uses PKCE and binds only to loopback
The OpenRouter onboarding flow generates a PKCE verifier and serves its callback from `socketserver.TCPServer(("localhost", port))`, so the token exchange is never reachable off-host.
Commit attribution is on by default
`attribute_author` and `attribute_committer` default to True, so aider's own commits remain identifiable in git history without the operator configuring anything.
Aider offers to gitignore its own artifacts
On startup aider detects its history and config files in a git repository and offers to add them to `.gitignore`, which keeps chat transcripts and local settings out of commits.
Log files found in the agent's workspace during this scan. Reviewing these files provides runtime evidence to complement the static analysis above.
| Path | Source | Content Type | Purpose | Last Modified | Status |
|---|---|---|---|---|---|
| .aider.chat.history.md | aider/io.py AiderIO.append_chat_history | free-form markdown transcript | Records user input, model output, and every confirmation question with the answer given | unknown | Inferred |
| .aider.input.history | aider/io.py prompt_toolkit FileHistory | plaintext history entries | Typed inputs and slash commands, including `/run <command>` lines added after execution | unknown | Inferred |
| .aider.llm.history | aider/io.py log_llm_history | plaintext request/response dump | Raw LLM traffic; written only when --llm-history-file is set | unknown | Inferred |
| ~/.aider/analytics.json | aider/analytics.py Analytics.save_data | JSON state file | Analytics user uuid and opt-in/permanently-disabled flags | unknown | Inferred |
| analytics event log (--analytics-log path) | aider/analytics.py Analytics.event | JSON lines | Telemetry events with event name, properties and timestamp; written only when --analytics-log is set | unknown | Inferred |
Each card represents one category and shows the top 3 findings. All items in the Findings section.
Each card represents one category and shows the top 3 findings. All items in the Findings section.
Overall maturity assessment across the six categories of the RAISE framework. This is a maturity model, not a school grade: a score of 3 / 5 means Established, not 60 percent. Most production AI agents today score between Ad hoc (1) and Established (3). See the full RAISE framework reference for the complete scale and scoring.
Maturity Scoring Rubric
Every score above is based on this scale. A score is a snapshot of observable posture — not a verdict on the people or team behind the system.
| Score | Label | Meaning |
|---|---|---|
| 5 | Exemplary | Best-in-class; automated, continuously tested, reference quality. Rarely achieved in shipping systems. |
| 4 | Strong | Comprehensive controls, active management, minor gaps. Production-ready. |
| 3 | Established | Documented controls consistently applied; known gaps accepted. A respectable baseline. |
| 2 | Partial | Some controls exist but coverage is incomplete; key gaps remain. |
| 1 | Ad hoc | Informal or inconsistent measures; relies on individual judgment. |
| 0 | Absent | No evidence this category is addressed at all. |