Skip to content

Harden local viewer and git source inspection#52

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1784936308-security-hardening
Open

Harden local viewer and git source inspection#52
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1784936308-security-hardening

Conversation

@devin-ai-integration

Copy link
Copy Markdown

Summary

Security pass over the Python implementation. Four fixes, all in the untrusted-input paths:

  • Stored XSS in the jobs viewer. inlineMarkdown in viewer/jobs.js escaped the label but passed the URL straight into href, so transcript text (agent output, fetched web pages, GitHub PR bodies) containing [x](javascript:...) executed on localhost:3927:
    html.replace(LINK_RE, (match, label, url) => {
      const href = safeHref(url);            // http:/https:/mailto:/#/… only
      return href === null ? match : `<a href="${escapeAttr(href)}" ...>${label}</a>`;
    });
    Unsafe links now render as literal (already-escaped) markdown text.
  • DNS rebinding against the unauthenticated viewer. server/security.py adds TrustedHostMiddleware restricted to loopback names when the server is bound to loopback, plus CSP / X-Frame-Options: DENY / nosniff / no-referrer on every response. When the user explicitly binds beyond loopback (serve --host 0.0.0.0) the Host check is skipped, so LAN access still works as before.
  • Generated API docs. /docs, /redoc, /openapi.json are disabled; they fall through to the viewer shell.
  • Argument injection into git. git:range:--output=<path> was forwarded as a positional arg to git log/git diff, turning read-only inspection into a write. require_revision_range now rejects ranges starting with -.

Not changed, checked and clean: SQL is fully parameterized (including the FTS builder in search_views.py), no shell=True anywhere, no hardcoded secrets (the PostHog key in integrations/telemetry/sender.py is a public project write key), API request models already reject negative limits and traversal-shaped paths, pip-audit on the locked dependency set reports no known vulnerabilities.

Why

The viewer serves repo content with no authentication and renders text produced by agents and third-party sources, so the browser is its real trust boundary: a javascript: link in a run transcript or a rebinding page on any site the user visits was enough to read or act on local wiki state. The git fix closes the one place where source input reached a subprocess as an option rather than data.

Verification

uv run ruff check .        # All checks passed
uv run pytest              # 569 passed
uv run codealmanac serve --no-open   # headers present, /docs falls through,
                                     # Host: evil.example -> 400, loopback -> 200
uvx pip-audit -r <(uv export --format requirements-txt --no-hashes)  # no known vulnerabilities

Docs and wiki

  • Not applicable.

Notes for reviewers

TestClient defaults to Host: testserver, which the loopback check rejects, so tests/test_server.py builds clients through a viewer_client helper pinned to http://127.0.0.1:3927. That is the only behavioral ripple: any non-loopback hostname pointed at a loopback-bound viewer (a custom /etc/hosts alias, some tunnel setups) now gets a 400 and needs --host to opt in.

Link to Devin session: https://app.devin.ai/sessions/7a1c08bc606c46ae89fef876a2673c3d
Requested by: @rohans0509

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@rohans0509 rohans0509 self-assigned this Jul 24, 2026
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

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.

1 participant