OSV 1.4.0 · github-reviewed · 修改于 2026-05-06 02:28
发布时间
2026-05-06 02:28
GitHub 审查时间
2026-05-06 02:28
NVD 发布时间
—
源文件
advisories/github-reviewed/2026/05/GHSA-g485-8j3v-p6x8/GHSA-g485-8j3v-p6x8.json
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.
The server fetches the README via GitHub's REST API and stores the raw markdown in MongoDB:
// 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:
// 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,
})
);
$sce.trustAsHtml() + ng-bind-htmlThe client fetches the raw README, parses it with renderMD() (which uses marked with sanitize: false), then bypasses AngularJS sanitization:
// 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;
// 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:
// 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.
/api/user and /api/repo/listREADME.md:# Innocent README
<img src=x onerror="alert(document.domain)">
Content-Disposition: attachment or in a sandboxed iframe on a separate origin$sce.trustAsHtml() with proper ngSanitize usageZhengyu Liu, Jingcheng Yang
2.2.0