From 4fdcdd4239ec15d14ee1facb01714926be0ffe1a Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Tue, 5 May 2026 00:51:52 +0200 Subject: [PATCH] fix(security): close open scanner alerts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dependabot/CodeQL #33 — postcss XSS GHSA-qx2v-qp2m-jg93: npm audit fix in graph-ui (8.5.8 -> 8.5.14, above the <8.5.10 vuln range) CodeQL #39 — TOCTOU race in artifact.c ensure_gitattributes(): Replace stat() + fopen() with open(O_WRONLY|O_CREAT|O_EXCL). Atomic create-only-if-absent closes the check-vs-write window. Falls through to merge driver setup if file already exists. CodeQL #55 — pip install not pinned in release.yml: Pin build==1.3.0 and twine==6.2.0. Comment explains why --require-hashes is not used (transitive-deps overhead). Dismissed (won't-fix): - #56 contents: write — required for 'gh release edit --draft=false'; no narrower permission exists. - #54-51 Crystal grammar warnings — vendored upstream code. - #50-40 Agda grammar warnings — vendored upstream code. --- .github/workflows/release.yml | 5 ++++- graph-ui/package-lock.json | 6 +++--- src/pipeline/artifact.c | 35 +++++++++++++++++++++++------------ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed4758713..51497a877 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -289,7 +289,10 @@ jobs: - name: Build PyPI distribution working-directory: pkg/pypi run: | - python -m pip install --upgrade build twine + # Pin to specific versions (typosquatting / supply-chain mitigation). + # OSSF scorecard prefers --require-hashes, but that needs full + # transitive deps; version pinning is the practical compromise. + python -m pip install --upgrade 'build==1.3.0' 'twine==6.2.0' python -m build - name: Publish to PyPI diff --git a/graph-ui/package-lock.json b/graph-ui/package-lock.json index d75d2ff2c..512eb82f6 100644 --- a/graph-ui/package-lock.json +++ b/graph-ui/package-lock.json @@ -5164,9 +5164,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "funding": [ { "type": "opencollective", diff --git a/src/pipeline/artifact.c b/src/pipeline/artifact.c index 4f343d297..b9ef94e6f 100644 --- a/src/pipeline/artifact.c +++ b/src/pipeline/artifact.c @@ -27,12 +27,15 @@ enum { #include #include +#include +#include #include #include #include #include #include #include +#include /* ── Helpers ──────────────────────────────────────────────────────── */ @@ -228,18 +231,26 @@ static void ensure_gitattributes(const char *repo_path) { char ga_path[CBM_SZ_4K]; artifact_path(ga_path, sizeof(ga_path), repo_path, ".gitattributes"); - struct stat st; - if (stat(ga_path, &st) == 0) { - return; /* already exists */ - } - - FILE *fp = fopen(ga_path, "w"); - if (fp) { - (void)fputs("# Auto-generated by codebase-memory-mcp\n" - "# Prevent merge conflicts on compressed artifact\n" CBM_ARTIFACT_FILENAME - " merge=ours binary\n", - fp); - (void)fclose(fp); + /* Atomic create-only-if-absent: O_EXCL closes the TOCTOU window + * between checking existence and writing. If the file exists, open + * fails with EEXIST and we leave it untouched. */ + int fd = open(ga_path, O_WRONLY | O_CREAT | O_EXCL, 0644); + if (fd < 0) { + if (errno != EEXIST) { + cbm_log_warn("artifact.gitattributes.open path=%s err=%s", ga_path, strerror(errno)); + } + /* fall through to merge driver setup either way */ + } else { + FILE *fp = fdopen(fd, "w"); + if (fp) { + (void)fputs("# Auto-generated by codebase-memory-mcp\n" + "# Prevent merge conflicts on compressed artifact\n" CBM_ARTIFACT_FILENAME + " merge=ours binary\n", + fp); + (void)fclose(fp); + } else { + (void)close(fd); + } } /* Best-effort: configure merge driver */