Skip to content

audit: DESC-05 keys by_manifest on absolute paths — leaks the auditor's home directory into committed artifacts #165

Description

@ArtRomanov

Summary

DESC-05 keys its by_manifest map on absolute filesystem paths, so every audit artifact that carries it records the home directory layout of whoever ran the audit. Since audit output is meant to be committed, that lands in version control permanently.

"value": {
  "total_direct_deps": 0,
  "by_manifest": {
    "/Users/<name>/<org>/<repo>/pyproject.toml": 0
  }
}

Two separate wort audit runs, on two different machines, each committed a different developer's home path this way. The second one had to be hand-edited before the pull request could be merged — which then made the artifact disagree with what the engine produces, since re-running render or patch-report restores the absolute form.

Where it comes from

skills/ai-readiness-audit/metrics/dependency_count.ts:

const manifests = findManifests(repoPath);   // returns absolute paths via join(dir, name)
...
for (const manifest of manifests) {
  const count = parseManifest(manifest, content);
  byManifest[manifest] = count;              // <-- absolute path used as the key
}

findManifests builds its results with join(dir, entry.name) starting from repoPath, so the keys inherit whatever absolute root the caller passed in. Nothing downstream relativises them.

Blast radius

Small and well-contained — this appears to be the only metric that leaks a path. Grepping a full 13-dimension run for the running user's home directory:

Artifact Occurrences
audit.json 2
descriptors.json 2
report.md 0
report.html 0
recommendations.md 0
judgments.json 0
collected/*.json 0

Both hits are the same DESC-05 value, once in the per-dimension file and once in the aggregate. The rendered reports do not surface it, so this is invisible until someone reads the JSON — or until it is already committed.

Why it matters beyond tidiness

  • It is committed by design. The skill writes into context/audits/<timestamp>/ inside the repository, and the workflow around it treats those directories as artifacts to review and merge. A leak here is not a temp-file leak.
  • It is not reproducible. The same repository audited by two people produces two different audit.json files that differ only by the auditor's username, so the artifacts cannot be diffed or verified against each other.
  • Hand-fixing breaks the provenance story. The reason collected/ and audit.json are committed at all is that a reader can re-derive the report from them. Editing the paths out by hand quietly severs that.

Suggested fix

Store by_manifest keys relative to repoPathrelative(repoPath, manifest) — so the example above becomes:

"by_manifest": { "pyproject.toml": 0 }

Relative keys are also more useful in a monorepo or in org mode, where services/api/pyproject.toml says something and /Users/someone/work/repo/services/api/pyproject.toml says the same thing plus noise.

Worth a general check that no other metric or collector embeds repoPath in a value it writes; the table above suggests DESC-05 is the only current offender, but the same join-then-store pattern would leak anywhere it is repeated.

Related

Environment

  • awos 2.4.2, engine at a98d515
  • Single-repo mode, macOS, Python project with one pyproject.toml

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