GHSA-g485-8j3v-p6x8
@tdurieux/anonymous_github Vulnerable to XSS via Unsanitized GitHub Repository Content Rendering in Anonymous GitHub Origin
Quick fix
GHSA-g485-8j3v-p6x8 — @tdurieux/anonymous_github: upgrade to the fixed version with the command below.
npm install @tdurieux/anonymous_github@2.3.0Details
### Summary
Anonymous GitHub fetches repository content (e.g., markdown files) from GitHub's API and renders it without sanitization. On the client side, markdown is parsed with `marked` (with `sanitize: false`) and injected into the DOM via `$sce.trustAsHtml()` + `ng-bind-html`, bypassing AngularJS's built-in XSS protection. An attacker can craft a malicious GitHub repository whose README executes arbitrary JavaScript in the Anonymous GitHub origin.
### Details
#### README fetched from GitHub API
The server fetches the README via GitHub's REST API and stores the raw markdown in MongoDB:
```typescript // https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/src/core/source/GitHubRepository.ts#L162-L174 const ghRes = await oct.repos.getReadme({ owner: this.owner, repo: this.repo, ref: selected?.commit, }); const readme = Buffer.from( ghRes.data.content, ghRes.data.encoding as BufferEncoding ).toString("utf-8"); selected.readme = readme; await model.save(); ```
It is then served to the client with no sanitization:
```typescript // https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/src/server/routes/repository-private.ts#L254-L260 return res.send( await repo.readme({ accessToken: token, force: req.query.force == "1", branch: req.query.branch as string, }) ); ```
#### Client-side rendering via `$sce.trustAsHtml()` + `ng-bind-html`
The client fetches the raw README, parses it with `renderMD()` (which uses `marked` with `sanitize: false`), then bypasses AngularJS sanitization:
```javascript // https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/public/script/app.js#L1219-L1226 const res = await $http.get(`/api/repo/${o.owner}/${o.repo}/readme`, { params: { force: force === true ? "1" : "0", branch: $scope.source.branch }, }); $scope.readme = res.data; ```
```javascript // https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/public/script/app.js#L1339-L1343 const html = renderMD( $scope.anonymize_readme, `https://github.com/${o.owner}/${o.repo}/raw/${$scope.source.branch}/` ); $scope.html_readme = $sce.trustAsHtml(html); // sink: bypasses Angular XSS protection ```
The `renderMD()` function explicitly disables sanitization:
```javascript // https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/public/script/utils.js#L165-L176 marked.setOptions({ sanitize: false, // HTML in markdown is preserved as-is // ... }); return marked.parse(md, { renderer }); ```
The resulting HTML is bound to the DOM via `ng-bind-html`, which trusts the string marked by `$sce.trustAsHtml()` and inserts it as innerHTML.
### Impact
1. **Stored XSS**: Any malicious GitHub repository can execute JavaScript in the Anonymous GitHub origin when a user anonymizes it or views its content 2. **Account Takeover**: Steal authentication tokens and session cookies 3. **Data Exfiltration**: Access other users' anonymization configurations and private repository data via `/api/user` and `/api/repo/list`
### Proof of Concept

1. Create a GitHub repository with a malicious `README.md`:
```markdown # Innocent README <img src=x onerror="alert(document.domain)"> ```
2. On Anonymous GitHub, enter the malicious repository URL to anonymize it 3. The XSS executes immediately when the README preview is rendered on the anonymize page
### Remediation
1. Sanitize markdown output with DOMPurify before rendering (the dependency already exists but is unused) 2. Serve HTML files with `Content-Disposition: attachment` or in a sandboxed iframe on a separate origin 3. Replace `$sce.trustAsHtml()` with proper `ngSanitize` usage 4. HTML-escape filenames and paths in directory listing templates 5. Add Content Security Policy headers
### Credits
Zhengyu Liu, Jingcheng Yang
Are you affected?
Enter the version of the package you're using.
Affected packages
2.2.0Fixed in: 2.3.0npm install @tdurieux/anonymous_github@2.3.0