chore: repo hygiene and security hardening - #12
Merged
Conversation
- Bump version to 0.5.0 in pyproject.toml (matches README badge) - Update Node requirement to 20+ (matches pdfjs-dist engine) - Remove uv.lock from .gitignore and commit lockfile - Self-host JetBrains Mono font, remove Google Fonts dependency - Fix false privacy claim in README comparison table - Add PDF download button to viewer header - Remove vendored system packages (natbib.sty, fancyhdr.sty) that violate LPPL redistribution terms — TeX Live provides them - Bundle acmart.dtx alongside acmart.cls per LPPL requirements - Add LPPL-1.3c license text and THIRD_PARTY_LICENSES manifest Co-Authored-By: Claude <noreply@anthropic.com>
Block requests to private/loopback/link-local/reserved IPs, validate URL schemes, and catch redirect-based bypasses via aiohttp TraceConfig. Also upgrades the PDF download icon to SVG with white color. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Replaces the upstream command tool with a sandboxed version that blocks network-exfiltration binaries (curl, wget, nc, ssh, etc.) and env-exposure commands. Adds -norc to all latexmk invocations to prevent .latexmkrc Perl code execution from untrusted paper directories. Co-Authored-By: Claude <noreply@anthropic.com>
- Replace trace-based redirect hook with manual redirect following that validates each Location header before connecting - Name downloaded PDFs after the paper title instead of generic paper.pdf - Remove stale fancyhdr.sty/natbib.sty from ICLR/ICML template configs Co-Authored-By: Claude <noreply@anthropic.com>
Subprocesses spawned by the agent command tool inherited the full server environment including API keys. Strip credential-shaped variables (*_API_KEY, *_TOKEN, *_SECRET, *_PASSWORD, *_CREDENTIAL, plus AWS keys and DATABASE_URL) while preserving S2_API_KEY for Semantic Scholar and all non-sensitive vars. Co-Authored-By: Claude <noreply@anthropic.com>
Document the defense-in-depth mitigations (command denylist, env scrubbing, SSRF protection, build isolation) and their limitations. Include recommendations for running against untrusted papers. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Hardens network and subprocess execution, improves repository licensing/versioning hygiene, and adds privacy-focused UI updates.
Changes:
- Adds SSRF, command, environment, and LaTeX build protections.
- Self-hosts fonts and improves PDF downloads.
- Updates versioning, lockfiles, template assets, licenses, and security documentation.
Reviewed changes
Copilot reviewed 20 out of 24 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
.gitignore |
Tracks the uv lockfile. |
README.md |
Updates requirements and security guidance. |
pyproject.toml |
Bumps the package version. |
uv.lock |
Adds locked Python dependencies. |
scripts/build.sh |
Disables latexmk configuration files. |
scripts/diff.py |
Hardens diff PDF compilation. |
scripts/validate.sh |
Removes shell interpolation from YAML loading. |
tests/test_ui.py |
Tests SSRF and command protections. |
ui/backend/agent.py |
Adds hardened command execution. |
ui/backend/server.py |
Adds titled PDF downloads. |
ui/backend/tools/web.py |
Adds SSRF checks and redirect validation. |
ui/frontend/index.html |
Removes Google Fonts requests. |
ui/frontend/src/index.css |
Configures the self-hosted font. |
ui/frontend/src/fonts/JetBrainsMono-latin.woff2 |
Provides the local font asset. |
ui/frontend/src/components/PdfViewer.tsx |
Adds the PDF download control. |
templates/LPPL-1.3c.txt |
Adds the LPPL license text. |
templates/SOURCES.md |
Documents template provenance. |
templates/THIRD_PARTY_LICENSES |
Adds the template license manifest. |
templates/acm/acmart.dtx |
Adds ACM class source. |
templates/iclr2026/template.yaml |
Removes stale bundled dependencies. |
templates/iclr2026/fancyhdr.sty |
Removes the vendored package. |
templates/iclr2026/natbib.sty |
Removes the vendored package. |
templates/icml2026/template.yaml |
Removes a stale bundled dependency. |
templates/icml2026/fancyhdr.sty |
Removes the vendored package. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Replace enumerated _is_internal checks with `not ip.is_global or ip.is_multicast` to catch CGNAT (100.64.0.0/10) and other non-public ranges. Add _safe_get redirect tests, fix __version__ to 0.5.0, and scope README SSRF claim to web_fetch only. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 21 out of 25 changed files in this pull request and generated 1 comment.
Suppressed comments (6)
tests/test_ui.py:498
- This test only checks that validation eventually raises; it would still pass if a regression sent the second request before validating the internal redirect. Assert that
session.getwas awaited exactly once so the security-critical ordering is covered.
with pytest.raises(ValueError, match="internal address"):
asyncio.run(_safe_get(mock_session, "https://example.com/go"))
ui/backend/agent.py:135
communicate()buffers all stdout in memory until the command exits or the 120-second timeout fires. An agent-invoked high-output command such asyescan therefore exhaust the server's memory well before timeout. Stream stdout with an explicit byte cap and terminate the process once that cap is reached.
try:
stdout, _ = await asyncio.wait_for(
proc.communicate(
input=input.encode() if input else None,
),
timeout=timeout,
ui/frontend/src/index.css:6
- The newly vendored JetBrains Mono font is OFL-1.1 third-party software, but the repository contains no OFL license/copyright notice and the root license otherwise presents the project as MIT. Add the font's license and attribution, and clarify that the font is excluded from the root MIT license.
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url('./fonts/JetBrainsMono-latin.woff2') format('woff2');
templates/iclr2026/template.yaml:8
- Existing projects initialized with the previous ICLR manifest already contain
fancyhdr.styandnatbib.sty. On a later switch,_get_old_extra_files()reads this updated manifest, so it no longer knows those files are template-owned and leaves them behind to shadow system packages. Add a legacy-removal/migration mechanism before dropping these ownership entries.
extra_files:
- iclr2026_conference.sty
- iclr2026_conference.bst
templates/icml2026/template.yaml:9
- Existing ICML projects created before this change already have a template-owned
fancyhdr.sty. Because old ownership is resolved from the current manifest, removing this entry means subsequent template switches never delete that stale file, and it can keep shadowing the system package. Preserve legacy ownership for cleanup or migrate it in the switching logic.
extra_files:
- icml2026.sty
- icml2026.bst
- algorithm.sty
README.md:164
- This guarantee applies only to the new arbitrary
commandtool. Fixed workflow tools usetools/subprocess.py:29-34, which starts build/sync/citation subprocesses with the full inherited environment, andS2_API_KEYis also explicitly preserved forcommand. Scope the documentation accordingly, or centralize scrubbing across both subprocess paths.
- **Environment scrubbing** — credential-shaped environment variables
(`*_API_KEY`, `*_TOKEN`, `*_SECRET`, `*_PASSWORD`, and AWS keys) are
stripped from subprocess environments. In-process tools like
`web_search` and `web_fetch` retain access to their own API keys.
- Filter agent-provided env vars through _is_sensitive_key before merging into scrubbed process environment - Add OFL-1.1 license for vendored JetBrains Mono font - Scope README env-scrub claim to the command tool only - Assert session.get call count in redirect-to-internal test Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
mkultraWasHere
added a commit
that referenced
this pull request
Aug 19, 2026
- SSRF protection: URL validation, manual redirect following with per-hop checks, CGNAT/multicast blocking via is_global - Command denylist: block network-exfiltration and env-exposure binaries - Environment scrubbing: strip credential-shaped vars from subprocess env (command tool only; fixed workflow tools inherit full env) - Build isolation: latexmk -norc to prevent .latexmkrc code execution - Script injection fix: pass paper path via sys.argv, not f-string - Self-host JetBrains Mono font (OFL-1.1), remove Google Fonts request - PDF download button with session-title filename - Template licensing: LPPL text, SOURCES.md provenance, third-party manifest, ACM acmart.dtx per LPPL distribution requirements - Remove vendored fancyhdr.sty/natbib.sty (use TeX Live system copies) - Version bump to 0.5.0, add uv.lock, security docs in README - CODEOWNERS: single owner to reduce review noise Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sys.argvin validate.sh (was shell-interpolated into Python), add-norcto all latexmk invocationscurl,wget,nc,ssh, etc.), scrub credential-shaped env vars from subprocess environmentsfancyhdr.sty/natbib.styfrom ICLR/ICMLextra_files(broke template switching)Test plan
task test)bash -cbypass blocking (5 formal tests + 28-case stress test)S2_API_KEY, non-sensitive var preservation (4 formal tests + 28-case stress test)🤖 Generated with Claude Code