Skip to content

fix(tracking): validate identifiers and keep server paths inside the storage directory - #948

Open
elijahbenizzy wants to merge 4 commits into
mainfrom
fix/tracking-identifier-validation
Open

elijahbenizzy wants to merge 4 commits into
mainfrom
fix/tracking-identifier-validation

Conversation

@elijahbenizzy

@elijahbenizzy elijahbenizzy commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Carries forward #795 by @andreahlert with his commit intact, and shares the identifier rule with the tracking client (#946).

  • Project and app identifiers in tracking server requests are validated against the same allowlist the client uses; invalid ones return HTTP 400.
  • Paths the server builds are resolved and kept inside the configured storage directory.
  • python -m burr.tracking.server.run binds to 127.0.0.1 by default, overridable with BURR_SERVER_HOST, matching what the burr CLI already does. The CLI help and module docstring note that the server has no built-in authentication.

23 tests added. Merge before #944, which documents this behavior.


Update after review. Every file the server opens under an application directory (graph.json, log.jsonl, metadata.json, children.jsonl) now goes through the same containment check as the directory; a symlinked file pointing outside the storage directory returns 400 (or is skipped with a warning in listings). Demo routers are mounted only when BURR_SERVER_DEMOS is truthy; burr-demo sets it, plain burr does not. Shares the widened identifier rule from #946 (any single path segment; see that PR for what is accepted and rejected).

andreahlert and others added 2 commits October 4, 2026 13:21
…storage directory

Add an allowlist check for project and app identifiers in LocalBackend and a
join helper that resolves paths and verifies they stay inside the configured
storage directory. Bind the standalone server to 127.0.0.1 by default.
…e server endpoints

Move the project/app identifier rule and the path join helper into
burr.tracking.common.identifiers (shared with LocalTrackingClient), keep the
LocalBackend wrappers that report failures as HTTP 400, honour BURR_SERVER_HOST
for the standalone server, and extend the tests to the FastAPI endpoints,
symlinked directories and client-style identifiers.

@sangkyoonnam sangkyoonnam left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server-side checks reject the traversal and encoding cases I sent to the backend endpoints, and pytest tests/tracking passes. The trailing-newline gap in identifiers.py that I noted on #946 applies here too, since the file is identical.

One upgrade question: some existing ids, like user@example.com, still appear in the app listing, but opening them now returns 400. What should users with data created before this change expect?

@skrawcz

skrawcz commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Two remaining hardening items before merging:

  1. _safe_join() currently validates only the application directory in get_application_logs(). The subsequently opened graph.json, log.jsonl, metadata.json, and children.jsonl paths are built with plain os.path.join(). Please apply containment checks to each final file path as well, and add tests where each fixed filename is a symlink outside the configured storage directory.
  2. The tracking server still mounts writable demo routers by default, and those demos use a separate hardcoded ~/.burr tracking client rather than the backend’s configured path. Please make demo routes explicitly opt-in, or at minimum document and test this separation. A production-capable tracking server should not expose mutation demos by default.

Also incorporate the identifier-regex fix from #946: use fullmatch() or an end anchor that does not accept a trailing newline.

I view file-level symlink handling as defense-in-depth because the storage directory is operator-controlled, but if this PR claims that every server path remains inside the configured storage directory, final file paths need to satisfy that claim too.

@elijahbenizzy

Copy link
Copy Markdown
Contributor Author

@skrawcz done: (1) the four fixed filenames are containment-checked individually, with a symlink test per file; (2) demo routers are opt-in via BURR_SERVER_DEMOS, which only burr-demo sets, with tests for both states and the CLI wiring; (3) same identifier helper as #946, control characters rejected. The two branches merge cleanly in either order; I ran tests/tracking on the merged tree. @sangkyoonnam if you want another pass, this is the state to test.

This branch has not been deployed

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

Labels

area/tracking Telemetry, tracing, OpenTelemetry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants