oni.git

oni

~ A static Git browser written in Rust.
git clone https://github.com/debuman/oni.git

SECURITY.md (9353B)

      1 # Security review
      2 
      3 Reviewed locally on 2026-11-12. This is a static Git browser, not a Git hosting
      4 service. No changes were published during this review.
      5 
      6 ## Trust boundaries
      7 
      8 Repository contents, Markdown, commit messages, author names, references, filenames,
      9 and GitHub metadata are treated as untrusted data. Repository code, hooks, external
     10 diff programs, text conversion commands, and submodule checkouts are not needed to
     11 generate the site.
     12 
     13 The operator, build scripts, process environment, Git configuration, cached bare
     14 repositories, and selected output root are trusted. A user able to replace these
     15 inputs or concurrently change filesystem paths has the builder's privileges. Path
     16 checks and atomic file replacement prevent ordinary preexisting symlink attacks;
     17 they are not an OS sandbox against a malicious process running as the same user.
     18 Do not point the generator at an attacker-supplied `.git` directory with arbitrary
     19 configuration. Fetch repository objects into a locally controlled bare repository.
     20 
     21 The generator and its C Markdown parser should run as an unprivileged account.
     22 `scripts/build.py` applies per-generator address-space and CPU limits and kills the
     23 whole process group after a wall-clock timeout. Direct binary invocation does not
     24 apply these OS limits; use the build script for the supported workflow.
     25 
     26 ## Findings and changes
     27 
     28 | Finding | Evidence and impact | Resolution |
     29 | --- | --- | --- |
     30 | Stored XSS in rendered READMEs | Raw scripts, event attributes, and JavaScript links survived rendering. Visiting a generated page could run repository-controlled script. | Sanitize with pinned Ammonia 4.2.4 and an explicit tag/attribute/URL allowlist. Reject unsafe metadata links. Add a script-blocking CSP to all HTML and preview responses. |
     31 | Local file disclosure through metadata | Worktree `description` and `url` files could be symlinks to files outside the repository. Their contents appeared in generated pages. | Read only regular, bounded files in the resolved Git metadata directory. Never read tracked worktree metadata overrides. |
     32 | Preview file disclosure and rebinding exposure | A symlink under the served root exposed an external file; an arbitrary Host header received HTTP 200. | Reject symlinks/junctions, traversal, alternate streams, and nonregular files. Validate Host, Origin, and Fetch Metadata. Bind to loopback and disable directory listings. |
     33 | Output symlink overwrite | Existing output file/directory links could redirect writes outside the intended tree. | Reject linked output directories and unsafe paths. Write new temporary files and atomically rename them instead of following destination file links. |
     34 | Active README assets and trusted-page rewriting | Any referenced blob could become a same-origin raw document; README rewriting also touched the page header. | Copy only signature-checked raster formats. Serve raw files with explicit MIME types and nosniff. Keep SVG on a separate origin. Rewrite only the sanitized README article. |
     35 | Unbounded input and process lifetime | Large blobs, metadata, Markdown, patches, or hung subprocesses could exhaust resources. | Add byte limits, generator process limits, HTTP connection limits/timeouts, and build subprocess timeouts with process-group cleanup. |
     36 | Outdated Git security baseline | Installed Ubuntu Git 2.53.0 predates the upstream 2026-11-10 fixes. | Build Git 2.56.1 privately from a checksum-pinned official release; select it for builds and refuse older baseline versions. System Git is unchanged. |
     37 
     38 Object IDs are also validated as hexadecimal SHA-1/SHA-256 values before they can
     39 become revision arguments, stream records, or output filenames. Online clone/fetch
     40 uses the validated GitHub HTTPS URL, enables object validation, disables hooks,
     41 credential helpers, non-HTTPS protocols, and submodule recursion.
     42 
     43 ## Resource limits
     44 
     45 | Input/process | Limit |
     46 | --- | --- |
     47 | Markdown README | 4 MiB input, 32 MiB MD4C output |
     48 | Individual source/image blob | 32 MiB |
     49 | Git metadata response or individual commit diff | 64 MiB |
     50 | Repository description/owner/URL metadata file | 16 KiB |
     51 | GitHub API page response | 8 MiB |
     52 | Generator process | 2 GiB virtual address space, 120 CPU seconds, 180 wall seconds |
     53 | Other build subprocess | 300 wall seconds unless explicitly overridden |
     54 | Preview HTTP server | 32 concurrent connections, 10-second socket timeout |
     55 
     56 Exceeding a limit fails the build before the staged site replaces the current
     57 preview. Limits mitigate resource exhaustion; they do not impose a whole-build disk
     58 quota or a total timeout across an arbitrary number of repositories. Keep adequate
     59 disk space and remove old `.cache/previous-*` snapshots when no longer needed.
     60 
     61 ## Verification
     62 
     63 The adversarial suite creates temporary local repositories and harmless marker
     64 payloads. Each XSS sample is generated independently, including raw script, event
     65 handlers, entity/control-character scheme obfuscation, data URLs, forms, iframe
     66 srcdoc, SVG, MathML mutation patterns, and DOM-clobbering attributes. Safe details,
     67 tasks, tables, and fenced code remain covered by regression tests.
     68 
     69 Other cases exercise metadata/output links, colon/backslash filenames, oversize
     70 input, fake raster data, active SVG/HTML, header preservation, encoded traversal,
     71 Host/Origin rejection, security headers, and raw-content MIME types. The full-site
     72 audit checks all generated pages and local links, parses Atom feeds, and opens every
     73 archive without extracting repository content.
     74 
     75 Completed results: 8 Rust unit tests, the generator regression suite, 9 adversarial
     76 tests under WSL, and 3 preview tests on native Windows passed. The Windows tests
     77 include a directory junction; file symlink cases run under WSL because the Windows
     78 account cannot create them. Four isolated Chromium browser cases ran without CSP
     79 and retained no executable payload or unsafe DOM nodes. The normal preview also
     80 loaded its stylesheet under the enforced CSP. The rebuilt site contained 21
     81 repositories, 1,159 HTML pages, 16,986 local links, and 21 readable archives, with no
     82 missing local links or disallowed executable elements detected by the site audit.
     83 
     84 Run the commands in [README.md](README.md#verification). Results and reproductions
     85 from this review are retained locally under `.cache/security-audit/`. The Cargo
     86 lockfile's 67 registry packages were queried against OSV on the review date; no
     87 matching published advisories were returned. That result does not prove that a
     88 dependency is free of unknown vulnerabilities. Native Git, MD4C, Python, OpenSSL,
     89 curl, and the browser also need ongoing security updates.
     90 
     91 ## Hosting requirements and remaining boundaries
     92 
     93 The local Python server is a development preview. Production uses GitHub Pages,
     94 which does not apply the preview server's custom response headers. Generated HTML
     95 still contains the script-blocking policy in `security/csp.txt` and a no-referrer
     96 meta policy, and repository HTML is sanitized before deployment. Meta CSP cannot
     97 enforce `frame-ancestors`, and HTML cannot set `X-Content-Type-Options` or
     98 `X-Frame-Options`. These HTTP-layer protections are not claimed for the direct
     99 GitHub Pages deployment.
    100 
    101 To enforce the full response policy, use a proxy or host that can set the CSP from
    102 `security/csp.txt` plus `frame-ancestors 'none'`, `X-Content-Type-Options: nosniff`,
    103 `X-Frame-Options: DENY`, and `Referrer-Policy: no-referrer`. Changing DNS alone does
    104 not add these headers. The DNS configuration and HTTPS certificate belong to the
    105 GitHub Pages deployment; no Cloudflare proxy rules are managed by this repository.
    106 
    107 CI validates pull requests with read-only repository permissions. Deployment runs
    108 only after a successful build on `main`, in a separate job with Pages/OIDC access.
    109 Checkout credentials are not persisted, actions are pinned, and build artifacts
    110 are checked for unsafe files and broken links before upload. The Pages packager
    111 retains the public `.github` repository but refuses `.git` metadata, symlinks, and
    112 special files. No deployment credentials are passed to repository content.
    113 
    114 External HTTPS images remain permitted and can disclose a visitor's IP address to
    115 their host. Outbound links and downloaded source archives contain repository data;
    116 sanitizing a page does not make external destinations or downloaded code trustworthy.
    117 Archives preserve repository files, including symlink entries; never execute or
    118 extract an untrusted archive without an appropriate separate boundary.
    119 
    120 No finite review can guarantee the absence of vulnerabilities. This review combines
    121 source inspection, reproducible exploits, regression tests, dependency checks, and
    122 local browser verification; it is not an exhaustive fuzzing campaign or a formal
    123 proof of the Rust/C boundary.
    124 
    125 ## Primary references
    126 
    127 - [Git security fixes announced on 2026-11-10](https://github.blog/open-source/git/git-security-vulnerabilities-announced-7/)
    128 - [Official Git source checksums](https://www.kernel.org/pub/software/scm/git/sha256sums.asc)
    129 - [Ammonia 4.2.4 API](https://docs.rs/ammonia/4.2.4/ammonia/struct.Builder.html)
    130 - [MD4C source and API](https://github.com/mity/md4c)
    131 - [Python HTTP server security considerations](https://docs.python.org/3/library/http.server.html#security-considerations)
    132 - [OSV batch query API](https://google.github.io/osv.dev/post-v1-querybatch/)