Skip to content

fix(models): reject path-traversal characters in artifact id fields - #187

Closed
jason020818 wants to merge 1 commit into
vouchdev:mainfrom
jason020818:fix/id-path-traversal
Closed

fix(models): reject path-traversal characters in artifact id fields#187
jason020818 wants to merge 1 commit into
vouchdev:mainfrom
jason020818:fix/id-path-traversal

Conversation

@jason020818

Copy link
Copy Markdown
Contributor

Problem

Every non-Source artifact — Claim, Page, Entity, Relation, Evidence, Session, Proposal — declares id: str with no validator. The storage layer maps those ids directly to filesystem paths via KBStore._yaml:

def _yaml(self, sub: str, obj_id: str) -> Path:
    return self.kb_dir / sub / f"{obj_id}.yaml"

An id like "../../etc/passwd" escapes kb_dir on any write operation (put_*, update_*, lifecycle helpers). Source.id was already constrained to a hex sha256; nothing similar existed for the others.

Fix

Add a module-level _safe_artifact_id helper that rejects /, \, .., and NUL bytes, and wire it into a _id_safe @field_validator on each affected model — mirroring the pattern Source already uses.

def _safe_artifact_id(v: str) -> str:
    if not v or not v.strip():
        raise ValueError("id must not be empty or whitespace-only")
    if "/" in v or "\\" in v or "\x00" in v or ".." in v:
        raise ValueError("id must not contain path-traversal characters")
    return v

Tests

New tests/test_model_id_safety.py with parametrized traversal payloads for all seven affected models. 155 total tests pass.

Closes #149

Closes vouchdev#149

`Evidence`, `Claim`, `Entity`, `Relation`, `Page`, `Session`, and
`Proposal` all declared bare `id: str` with no validation. The storage
layer maps those ids directly to filesystem paths:

    def _yaml(self, sub, obj_id):
        return self.kb_dir / sub / f"{obj_id}.yaml"

An id like `"../../etc/passwd"` would produce a path escaping `kb_dir`
on any write operation (`put_*`, `update_*`, lifecycle helpers). Bundle
import was already guarded by `_safe_member_path`; model construction was
not.

Add a module-level `_safe_artifact_id` helper that rejects `/`, `\`,
`..`, and NUL bytes, and wire it into a `_id_safe` `@field_validator` on
each affected model — mirroring the pattern `Source` already uses for its
hex-sha256 constraint. New `tests/test_model_id_safety.py` covers all
seven models with parametrized traversal payloads.
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jaso0n0818, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 54 minutes and 17 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a7223e71-21d6-416c-b2e6-c3c20979cbaa

📥 Commits

Reviewing files that changed from the base of the PR and between 3beb821 and a3bd341.

📒 Files selected for processing (2)
  • src/vouch/models.py
  • tests/test_model_id_safety.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jason020818 jason020818 closed this Jun 9, 2026
@jason020818

Copy link
Copy Markdown
Contributor Author

Closing to focus review bandwidth on higher-priority, smaller bugfix PRs in ragflow/allways/gittensor. Will reopen or resubmit if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

validation gap: artifact ids accept path-traversal strings and reach filesystem paths unsanitised in storage operations

1 participant