Skip to content

fix(security): resolve CodeQL code-scanning alerts - #635

Merged
h4yfans merged 1 commit into
mainfrom
fix/codeql-alerts
Jun 30, 2026
Merged

fix(security): resolve CodeQL code-scanning alerts#635
h4yfans merged 1 commit into
mainfrom
fix/codeql-alerts

Conversation

@h4yfans

@h4yfans h4yfans commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Resolves the 13 open CodeQL code-scanning alerts with minimal, correct security fixes. Each file was read before editing.

Fixes (11 alerts)

js/clear-text-logging x3 — apps/landing/paddle-debug.mjs:21

Throwaway diagnostic script logged the Paddle API key (prefix/suffix/length) in cleartext. Grepped the repo: no references anywhere. Deleted the file.

js/incomplete-multi-character-sanitization x3

A single replace() pass stripping HTML tags/comments can be defeated because removing one match can re-form another from the surrounding text. Fixed by looping the strip until the string stops changing. Behavior for valid input is unchanged; covered by existing tests.

  • apps/desktop/src/main/lib/html-to-plain-text.ts:47 (tag strip)
  • packages/app-core/src/markdown.ts:30 (HTML comment strip)
  • apps/desktop/src/main/vault/frontmatter.ts:481 (HTML comment strip)

js/insecure-temporary-file x3

CodeQL taint-flows an OS-temp-dir source (test setup uses fs.mkdtempSync(os.tmpdir())) into these production write sinks. The already-clean generate-rpc-bindings.ts writeFileAtomically is exempt because it opens with fs.openSync(tempPath, 'wx', 0o600) — exclusive flag + owner-only mode. Applied the same wx + 0o600 pattern consistently:

  • apps/desktop/src/main/vault/file-ops.ts:36 — temp write now { encoding, mode: 0o600, flag: 'wx' } (random name + rename already present).
  • apps/desktop/src/main/vault/init.ts:98 — added mode: 0o600 (keeps create-only wx semantics, no clobber).
  • apps/desktop/src/main/vault/vault-preferences.ts:112 — converted the direct overwrite into an atomic uniquely-named temp write (wx + 0o600) then rename.

js/http-to-file-accessapps/desktop/src/main/import/html/html-importer.ts

HTML import downloaded remote <img> refs (await fetch(ref)) and wrote the bytes into the vault, allowing SSRF / writing internal-service content. Added safeRemoteAssetUrl(): restricts to https, rejects loopback / private / link-local hosts; the http branch now skips unsafe URLs and fetches the validated URL. Destination filename was already sanitized (path.basename + sanitizeFilename), so it stays inside the attachments dir.

js/bad-code-sanitizationapps/desktop/scripts/generate-rpc-bindings.ts:78

JSON.stringify used to build generated code leaves U+2028/U+2029 (JS line terminators) unescaped, which could break out of a generated string literal. Added jsStringLiteral() that escapes them and routed channel/domain/method/property-key literals through it. Generated output is byte-identical (pnpm ipc:generate produced no diff; pnpm ipc:check passes).

Dismissed (2 alerts)

js/file-access-to-http x2 — apps/desktop/tests/e2e/fixtures/claude:56,58

Test-only E2E fixture (a fake claude CLI), never shipped. It simulates the real Claude CLI reading its --mcp-config and POSTing to the local Memry MCP server — the file-to-http flow is the fixture's entire purpose, and the URL is already constrained to loopback via getLoopbackUrl(). Dismissed as "won't fix".

Verification

  • pnpm ipc:generate -> no diff; pnpm ipc:check passes.
  • pnpm --filter @memry/app-core test (markdown 4/4) and typecheck pass.
  • Affected desktop main tests pass: PASS (164) FAIL (0) across file-ops, init, vault-preferences, html-importer, html-to-plain-text, attachments.
  • pnpm --filter @memry/desktop typecheck:node passes.
  • ESLint clean on changed files (the one no-control-regex warning in html-to-plain-text.ts is the pre-existing U+0000 HEADING_MARK regex owned by a sibling lint PR).

- clear-text-logging (x3): delete leftover apps/landing/paddle-debug.mjs
  diagnostic that logged Paddle API key prefix/suffix/length. No references.
- incomplete-multi-character-sanitization (x3): loop the HTML tag/comment
  strip until the string stops changing so a re-formed match can't survive
  a single pass (html-to-plain-text.ts, app-core markdown.ts, frontmatter.ts).
- insecure-temporary-file (x3): write configs/atomic files via an exclusive
  ('wx') open with owner-only mode 0o600, matching the already-clean
  generate-rpc-bindings writeFileAtomically (file-ops, init, vault-preferences).
- http-to-file-access: restrict remote HTML-import asset downloads to https
  and reject loopback/private/link-local hosts before fetching into the vault
  (html-importer.ts); destination filename already sanitized.
- bad-code-sanitization: escape U+2028/U+2029 in JSON.stringify'd values used
  to build generated RPC bindings (generate-rpc-bindings.ts). Output unchanged.

Two js/file-access-to-http alerts on the test-only e2e claude fixture
dismissed (loopback-guarded, never shipped).
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
memry-docs Ready Ready Preview, Comment Jun 30, 2026 1:39am
memrynote-landing Ready Ready Preview, Comment Jun 30, 2026 1:39am

@github-actions github-actions Bot added the bug Something isn't working label Jun 30, 2026
@h4yfans
h4yfans marked this pull request as ready for review June 30, 2026 09:23
@h4yfans
h4yfans merged commit 809cb80 into main Jun 30, 2026
14 of 16 checks passed
h4yfans added a commit that referenced this pull request Jun 30, 2026
Repairs failures introduced by the #635-639 batch merge:

- guard app.setAboutPanelOptions (macOS/Linux only) — fixes a Windows
  startup crash and the main-process unit-test cascade
- voice-recorder: init waveform ref at creation, not during render
  (react-hooks/refs)
- video-player: translate the video aria-label (common:media.video)
- use-feature-flags, calendar: drop literal extractErrorMessage fallbacks
  (i18n lint rule + i18n check --max-todo 0)
- tests: add useSidebar / useTheme / onMenuCommand mocks for the new menu
  commands hook; fix the sync vault-id mock (getOrCreateVaultUuid is sync)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant