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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions