{"id":6269616,"name":"@tdurieux/anonymous_github","ecosystem":"npm","description":"Anonymise Github repositories for double-anonymous reviews","homepage":"https://github.com/tdurieux/anonymous_github#readme","licenses":"GPL-3.0","normalized_licenses":["GPL-3.0"],"repository_url":"https://github.com/tdurieux/anonymous_github","keywords_array":[],"namespace":"tdurieux","versions_count":5,"first_release_published_at":"2023-02-06T14:56:01.633Z","latest_release_published_at":"2026-04-24T14:17:11.423Z","latest_release_number":"2.3.0","last_synced_at":"2026-05-17T11:14:32.679Z","created_at":"2023-02-06T16:33:21.750Z","updated_at":"2026-05-18T05:15:05.948Z","registry_url":"https://www.npmjs.com/package/@tdurieux/anonymous_github","install_command":"npm install @tdurieux/anonymous_github","documentation_url":null,"metadata":{"funding":{"url":"https://github.com/sponsors/tdurieux"},"dist-tags":{"latest":"2.3.0"}},"repo_metadata":{"id":37451024,"uuid":"105154070","full_name":"tdurieux/anonymous_github","owner":"tdurieux","description":"Anonymous Github is a proxy server to support anonymous browsing of Github repositories for open-science code and data.","archived":false,"fork":false,"pushed_at":"2026-05-12T18:00:53.000Z","size":20247,"stargazers_count":2068,"open_issues_count":11,"forks_count":82,"subscribers_count":11,"default_branch":"main","last_synced_at":"2026-05-12T19:35:43.946Z","etag":null,"topics":["anonymous","double-anonymous","double-blind","open-science","peer-review"],"latest_commit_sha":null,"homepage":"https://anonymous.4open.science/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tdurieux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"tdurieux","patreon":null,"open_collective":null,"ko_fi":"tdurieux","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":"tdurieux","otechie":null,"custom":null}},"created_at":"2017-09-28T13:47:32.000Z","updated_at":"2026-05-12T18:00:58.000Z","dependencies_parsed_at":"2024-03-28T11:32:17.186Z","dependency_job_id":"1980b3de-0d74-46b7-8d4e-b3027cb518c8","html_url":"https://github.com/tdurieux/anonymous_github","commit_stats":{"total_commits":417,"total_committers":6,"mean_commits":69.5,"dds":0.05035971223021585,"last_synced_commit":"fa189949a628d8ad2073f9c242a66845ee7f393e"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/tdurieux/anonymous_github","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdurieux","download_url":"https://codeload.github.com/tdurieux/anonymous_github/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33136235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T09:28:26.183Z","status":"ssl_error","status_checked_at":"2026-05-17T09:27:52.702Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"},"owner_record":{"login":"tdurieux","name":"Thomas Durieux","uuid":"5577568","kind":"user","description":"","email":"","website":"https://durieux.me","location":null,"twitter":"thodurieux","company":null,"icon_url":"https://avatars.githubusercontent.com/u/5577568?u=6eb7ef170983508226f0640a6d760894230291ec\u0026v=4","repositories_count":132,"last_synced_at":"2024-04-15T08:05:00.807Z","metadata":{"has_sponsors_listing":true},"html_url":"https://github.com/tdurieux","funding_links":["https://github.com/sponsors/tdurieux"],"total_stars":1480,"followers":164,"following":0,"created_at":"2022-11-03T18:57:34.398Z","updated_at":"2024-04-15T08:05:18.121Z","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdurieux","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdurieux/repositories"},"tags":[{"name":"v2.2.0","sha":"696a465d5c5919d224a74e23c3206c9b84febce1","kind":"tag","published_at":"2023-08-28T12:46:54.000Z","download_url":"https://codeload.github.com/tdurieux/anonymous_github/tar.gz/v2.2.0","html_url":"https://github.com/tdurieux/anonymous_github/releases/tag/v2.2.0","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/tdurieux/anonymous_github@v2.2.0","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2.2.0","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2.2.0/manifests"},{"name":"v2.1.5","sha":"d8de3f189a8ca8233677293da221135dfc8eb528","kind":"commit","published_at":"2023-08-28T10:12:16.000Z","download_url":"https://codeload.github.com/tdurieux/anonymous_github/tar.gz/v2.1.5","html_url":"https://github.com/tdurieux/anonymous_github/releases/tag/v2.1.5","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/tdurieux/anonymous_github@v2.1.5","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2.1.5","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2.1.5/manifests"},{"name":"v2.1.1","sha":"c84df5c8e929877794d50aa2188b9e1f5dbf34c5","kind":"tag","published_at":"2023-02-07T08:04:11.000Z","download_url":"https://codeload.github.com/tdurieux/anonymous_github/tar.gz/v2.1.1","html_url":"https://github.com/tdurieux/anonymous_github/releases/tag/v2.1.1","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/tdurieux/anonymous_github@v2.1.1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2.1.1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2.1.1/manifests"},{"name":"v2","sha":"ee4a20286d707473b78f0454b23ff4eecc86ba02","kind":"commit","published_at":"2021-08-13T05:22:47.000Z","download_url":"https://codeload.github.com/tdurieux/anonymous_github/tar.gz/v2","html_url":"https://github.com/tdurieux/anonymous_github/releases/tag/v2","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/tdurieux/anonymous_github@v2","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v2/manifests"},{"name":"v1","sha":"c40da90044fe737d0a35c8710a9e6ae35bed9c93","kind":"commit","published_at":"2021-08-13T05:19:11.000Z","download_url":"https://codeload.github.com/tdurieux/anonymous_github/tar.gz/v1","html_url":"https://github.com/tdurieux/anonymous_github/releases/tag/v1","dependencies_parsed_at":null,"dependency_job_id":null,"purl":"pkg:github/tdurieux/anonymous_github@v1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/tags/v1/manifests"}]},"repo_metadata_updated_at":"2026-05-17T11:14:34.309Z","dependent_packages_count":0,"downloads":217,"downloads_period":"last-month","dependent_repos_count":0,"rankings":{"downloads":29.656145275930335,"dependent_repos_count":25.30552159382132,"dependent_packages_count":32.889739249478886,"stargazers_count":3.170066843503076,"forks_count":5.539774191566471,"average":19.312249430860017},"purl":"pkg:npm/%40tdurieux/anonymous_github","advisories":[{"uuid":"GSA_kwCzR0hTQS1nNDg1LThqM3YtcDZ4OM4ABWLo","url":"https://github.com/advisories/GHSA-g485-8j3v-p6x8","title":"@tdurieux/anonymous_github Vulnerable to XSS via Unsanitized GitHub Repository Content Rendering in Anonymous GitHub Origin","description":"### Summary\n\nAnonymous 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.\n\n### Details\n\n#### README fetched from GitHub API\n\nThe server fetches the README via GitHub's REST API and stores the raw markdown in MongoDB:\n\n```typescript\n// https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/src/core/source/GitHubRepository.ts#L162-L174\nconst ghRes = await oct.repos.getReadme({\n  owner: this.owner,\n  repo: this.repo,\n  ref: selected?.commit,\n});\nconst readme = Buffer.from(\n  ghRes.data.content,\n  ghRes.data.encoding as BufferEncoding\n).toString(\"utf-8\");\nselected.readme = readme;\nawait model.save();\n```\n\nIt is then served to the client with no sanitization:\n\n```typescript\n// https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/src/server/routes/repository-private.ts#L254-L260\nreturn res.send(\n  await repo.readme({\n    accessToken: token,\n    force: req.query.force == \"1\",\n    branch: req.query.branch as string,\n  })\n);\n```\n\n#### Client-side rendering via `$sce.trustAsHtml()` + `ng-bind-html`\n\nThe client fetches the raw README, parses it with `renderMD()` (which uses `marked` with `sanitize: false`), then bypasses AngularJS sanitization:\n\n```javascript\n// https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/public/script/app.js#L1219-L1226\nconst res = await $http.get(`/api/repo/${o.owner}/${o.repo}/readme`, {\n  params: { force: force === true ? \"1\" : \"0\", branch: $scope.source.branch },\n});\n$scope.readme = res.data;\n```\n\n```javascript\n// https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/public/script/app.js#L1339-L1343\nconst html = renderMD(\n  $scope.anonymize_readme,\n  `https://github.com/${o.owner}/${o.repo}/raw/${$scope.source.branch}/`\n);\n$scope.html_readme = $sce.trustAsHtml(html);  // sink: bypasses Angular XSS protection\n```\n\nThe `renderMD()` function explicitly disables sanitization:\n\n```javascript\n// https://github.com/tdurieux/anonymous_github/blob/b2d77faa6c6f35ad9ae6ed46e3a3fa4681ac84c2/public/script/utils.js#L165-L176\nmarked.setOptions({\n  sanitize: false,  // HTML in markdown is preserved as-is\n  // ...\n});\nreturn marked.parse(md, { renderer });\n```\n\nThe resulting HTML is bound to the DOM via `ng-bind-html`, which trusts the string marked by `$sce.trustAsHtml()` and inserts it as innerHTML.\n\n### Impact\n\n1. **Stored XSS**: Any malicious GitHub repository can execute JavaScript in the Anonymous GitHub origin when a user anonymizes it or views its content\n2. **Account Takeover**: Steal authentication tokens and session cookies\n3. **Data Exfiltration**: Access other users' anonymization configurations and private repository data via `/api/user` and `/api/repo/list`\n\n### Proof of Concept\n\n![poc-xss-anonymous-github](https://github.com/user-attachments/assets/c1bf3ed9-4e1e-4c8e-87f0-782a8d5f6ead)\n\n1. Create a GitHub repository with a malicious `README.md`:\n\n```markdown\n# Innocent README\n\u003cimg src=x onerror=\"alert(document.domain)\"\u003e\n```\n\n2. On Anonymous GitHub, enter the malicious repository URL to anonymize it\n3. The XSS executes immediately when the README preview is rendered on the anonymize page\n\n### Remediation\n\n1. Sanitize markdown output with DOMPurify before rendering (the dependency already exists but is unused)\n2. Serve HTML files with `Content-Disposition: attachment` or in a sandboxed iframe on a separate origin\n3. Replace `$sce.trustAsHtml()` with proper `ngSanitize` usage\n4. HTML-escape filenames and paths in directory listing templates\n5. Add Content Security Policy headers\n\n### Credits\n\nZhengyu Liu, Jingcheng Yang","origin":"UNSPECIFIED","severity":"HIGH","published_at":"2026-05-05T18:28:32.000Z","withdrawn_at":null,"classification":"GENERAL","cvss_score":8.1,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N","references":["https://github.com/tdurieux/anonymous_github/security/advisories/GHSA-g485-8j3v-p6x8","https://github.com/advisories/GHSA-g485-8j3v-p6x8"],"source_kind":"github","identifiers":["GHSA-g485-8j3v-p6x8"],"repository_url":null,"blast_radius":0.0,"created_at":"2026-05-05T19:00:08.699Z","updated_at":"2026-05-18T05:00:45.160Z","epss_percentage":null,"epss_percentile":null,"api_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1nNDg1LThqM3YtcDZ4OM4ABWLo","html_url":"https://advisories.ecosyste.ms/advisories/GSA_kwCzR0hTQS1nNDg1LThqM3YtcDZ4OM4ABWLo","packages":[{"ecosystem":"npm","package_name":"@tdurieux/anonymous_github","versions":[{"first_patched_version":"2.3.0","vulnerable_version_range":"= 2.2.0"}],"purl":"pkg:npm/%40tdurieux%2Fanonymous_github"}],"related_packages_url":"https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1nNDg1LThqM3YtcDZ4OM4ABWLo/related_packages","related_advisories":[]}],"docker_usage_url":"https://docker.ecosyste.ms/usage/npm/@tdurieux/anonymous_github","docker_dependents_count":null,"docker_downloads_count":null,"usage_url":"https://repos.ecosyste.ms/usage/npm/@tdurieux/anonymous_github","dependent_repositories_url":"https://repos.ecosyste.ms/api/v1/usage/npm/@tdurieux/anonymous_github/dependencies","status":null,"funding_links":["https://github.com/sponsors/tdurieux","https://ko-fi.com/tdurieux","https://issuehunt.io/r/tdurieux"],"critical":null,"issue_metadata":{"last_synced_at":"2026-05-06T09:12:28.956Z","issues_count":349,"pull_requests_count":51,"avg_time_to_close_issue":4421663.796703297,"avg_time_to_close_pull_request":1519463.8387096773,"issues_closed_count":182,"pull_requests_closed_count":31,"pull_request_authors_count":9,"issue_authors_count":317,"avg_comments_per_issue":1.4297994269340975,"avg_comments_per_pull_request":0.21568627450980393,"merged_pull_requests_count":27,"bot_issues_count":0,"bot_pull_requests_count":39,"past_year_issues_count":68,"past_year_pull_requests_count":1,"past_year_avg_time_to_close_issue":44153.666666666664,"past_year_avg_time_to_close_pull_request":null,"past_year_issues_closed_count":9,"past_year_pull_requests_closed_count":0,"past_year_pull_request_authors_count":1,"past_year_issue_authors_count":65,"past_year_avg_comments_per_issue":0.27941176470588236,"past_year_avg_comments_per_pull_request":0.0,"past_year_bot_issues_count":0,"past_year_bot_pull_requests_count":0,"past_year_merged_pull_requests_count":0,"issues_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdurieux%2Fanonymous_github/issues","maintainers":[{"login":"tdurieux","count":4,"url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors/tdurieux"},{"login":"monperrus","count":1,"url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors/monperrus"}],"active_maintainers":[]},"versions_url":"https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/@tdurieux%2Fanonymous_github/versions","version_numbers_url":"https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/@tdurieux%2Fanonymous_github/version_numbers","latest_version_url":"https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/@tdurieux%2Fanonymous_github/latest_version","dependent_packages_url":"https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/@tdurieux%2Fanonymous_github/dependent_packages","related_packages_url":"https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/@tdurieux%2Fanonymous_github/related_packages","codemeta_url":"https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/@tdurieux%2Fanonymous_github/codemeta","maintainers":[{"uuid":"tdurieux","login":"tdurieux","name":null,"email":"public@durieux.me","url":null,"packages_count":10,"html_url":"https://www.npmjs.com/~tdurieux","role":null,"created_at":"2023-02-06T16:42:55.146Z","updated_at":"2023-02-06T16:42:55.146Z","packages_url":"https://packages.ecosyste.ms/api/v1/registries/npmjs.org/maintainers/tdurieux/packages"}]}