Skip to content

[P1] Symlink aliases bypass audit-log and ADR Write/Edit guards #162

Description

@tg12

Severity: P1 critical

Problem

The Write/Edit guards decide whether a file is protected by matching the raw file_path string. They do not resolve symlinks before checking whether the target is under .codearbiter/.

Source evidence:

  • plugins/ca/hooks/pre-write.py:25 reads tool_input.file_path and normalizes separators only.
  • plugins/ca/hooks/pre-write.py:29-42 blocks only when is_audit_log(fpath) or is_decisions_path(fpath) matches that raw path.
  • plugins/ca/hooks/pre-edit.py:29-34 and pre-edit.py:64-70 do the same raw-path checks.
  • _hooklib.repo_rel() already resolves real paths in plugins/ca/hooks/_hooklib.py:216-231, but pre-write/pre-edit do not use it.

A symlink whose visible path does not contain .codearbiter/ can point directly at .codearbiter, and the Write/Edit tools will follow the symlink after the hook allows the operation.

Reproduction

In a throwaway enabled repo:

  1. Create .codearbiter/overrides.log containing seed.
  2. Create a symlink alias -> .codearbiter.
  3. Invoke pre-write.py with file_path set to <repo>/alias/overrides.log.
  4. Invoke pre-edit.py with file_path set to the same symlinked path.

Observed locally:

pre-write.py <repo>/alias/overrides.log
exit 0
stderr

pre-edit.py <repo>/alias/overrides.log
exit 0
stderr

pre-write.py <repo>/.codearbiter/overrides.log
exit 2
stderr BLOCKED [H-05]: The .codearbiter audit logs ... are append-only ...

The canonical path blocks, while the symlink alias to the same target is allowed.

Impact

An agent can overwrite or edit append-only audit logs and ADR files through a symlink alias, bypassing H-05 and H-11. This breaks the audit-trail and immutable-decision guarantees after a single unguarded symlink setup step.

Smallest credible fix

Resolve protected file targets before classification:

  • In pre-write/pre-edit, compute the repo-relative real path with the same repo_rel()/realpath approach used elsewhere.
  • Apply H-05/H-11 to both the raw path and the resolved repo-relative target.
  • Add tests for a symlinked directory and a symlinked file targeting .codearbiter/overrides.log and .codearbiter/decisions/*.md.
  • Consider blocking symlink creation that targets protected .codearbiter paths through the Bash guard as defense in depth.

Duplicate check

Checked existing issues with:

gh issue list --repo arbiterForge/codeArbiter --state all --search "symlink audit log overrides.log pre-write pre-edit ADR decisions bypass"

No matching issue was returned.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions