Skip to content

fix(security): resolve code-scanning alerts (TOCTOU, HTML sanitization, actions pinning) - #478

Open
BillyOutlast wants to merge 1 commit into
Drop-OSS:developfrom
Heretek-AI:pr/security-fixes
Open

fix(security): resolve code-scanning alerts (TOCTOU, HTML sanitization, actions pinning)#478
BillyOutlast wants to merge 1 commit into
Drop-OSS:developfrom
Heretek-AI:pr/security-fixes

Conversation

@BillyOutlast

Copy link
Copy Markdown

Summary

Resolves all open CodeQL code-scanning alerts on this repository across three classes of findings.

1. File-system race conditions (js/file-system-race) — server/server/internal/objects/fsBackend.ts

FsObjectBackend used existsSync check-then-use patterns, leaving a TOCTOU window between checking a path and acting on it. Rewritten to:

  • Open the file handle first and perform every subsequent operation (stat, read stream, write) through that same fd
  • Use exclusive-create (wx) flags for object + metadata files so concurrent creates cannot clobber each other
  • Use r+ flags for writes so they only ever target files created via create()

2. HTML sanitization in Steam metadata (js/incomplete-multi-character-sanitization, js/double-escaping) — server/server/internal/metadata/steam.ts

The entity decoder applied sequential replace() passes, so a decoded & could recombine into new entities (double-unescaping), and <script> decoded to live markup. The decoder now:

  • Decodes all entities in a single pass so decoded characters can't form new entities
  • Never emits angle brackets: </> are excluded from the decode set and dropped outright, and numeric references encoding 0x3C/0x3E (<, <, zero-padded variants) are dropped too
  • Removes any residual < after decoding, since legitimate markup is already converted to Markdown earlier in the pipeline

HTML comment removal also consumes unterminated comment openers (<!--> tricks).

3. CI supply-chain hardening (actions/unpinned-tag, actions/missing-workflow-permissions)

  • All GitHub Actions pinned to full commit SHAs (original tag kept as an inline comment for readability)
  • Explicit permissions: contents: read added to workflows missing it

Also included

7 eslint errors that fire under current eslint-plugin-vue / typescript-eslint versions (vue/no-multiple-template-root from a commented-out template block in pages/account/index.vue, dead initializers flagged by no-useless-assignment) — fixed so CI stays green regardless of lockfile drift. The commented-out account-page layout lives in git history.

Verification

  • pnpm run typecheck — clean
  • pnpm run build — passes
  • pnpm run lint — 0 errors (11 pre-existing warnings unchanged)
  • Adversarial tests against the sanitizer confirm no input form (named entities, double-escaped, decimal/hex/zero-padded numeric references, raw tags, comment tricks) can produce a < in output

CodeQL flagged three classes of issues; this resolves all of them.

js/file-system-race (server/server/internal/objects/fsBackend.ts):
Replace existsSync check-then-use patterns with exception-based access.
All reads/writes now go through a single opened file descriptor
(fs.promises.open -> handle.stat()/createWriteStream/handle.write), so
there is no window between checking a path and using it. Object and
metadata creation uses exclusive-create ('wx') flags so concurrent
creates cannot clobber each other, and writes use 'r+' flags so they
only target files created via create().

js/incomplete-multi-character-sanitization +
js/double-escaping (server/server/internal/metadata/steam.ts):
Rewrite the Steam HTML entity decoder as a single-pass replacement so a
decoded '&' cannot recombine with later passes into new entities
(double-unescaping). Angle brackets are never emitted: &lt;/&gt; are
excluded from the decode set and dropped, numeric references encoding
0x3C/0x3E (&Drop-OSS#60;, &#x3C;, zero-padded variants) are dropped too, and any
residual '<' characters are removed outright since legitimate markup is
already converted to Markdown earlier in the pipeline. HTML comment
removal consumes both closed and unterminated comment openers.

actions/unpinned-tag + actions/missing-workflow-permissions:
Pin all GitHub Actions to full commit SHAs (original tag kept as an
inline comment) across all workflow files, and add explicit workflow-
level permissions to droplet-ci.yml.

Also fixes 7 eslint errors (vue/no-multiple-template-root,
no-useless-assignment) that fire under current plugin versions, so CI
stays green regardless of lockfile drift.

Verified: typecheck clean, build passes, eslint 0 errors, ast-grep scan
clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant