Code Audit Report — 2026-04-23 #1

Closed
opened 2026-04-23 09:41:38 +02:00 by uwe.admin · 7 comments
Owner

Code Audit Report — 2026-04-23

Automated audit of webapp-scaffold covering 23 audit categories.

webapp-scaffold is a small (~750 LOC, 8 source files) shared npm library (@uschuster/webapp-scaffold) providing frontend build glue for derived projects: Vite config factories, an Orval fetch mutator (createCoreFetch), a tiny i18n store, and three codegen/build CLIs (fetch-openapi.sh, postprocess-openapi.py, inject-hashed-filenames.py). It is not an application: no Oat++ backend, no SQLite, no authentication, no controllers, no user input handling, no file uploads, no server-side logging, no tests. Most of the 23 prompts target application concerns that simply do not exist here; findings reflect what is present.

Executive Summary

  • Critical: 0
  • High: 0
  • Medium: 3
  • Low: 6
  • Informational / N/A: 12 audits do not apply (no backend / DB / auth / etc.)

The scaffold is small, focused, well-commented, and has no obvious security issues in its own code. The main gaps are library hygiene: no tests, prepare script swallows tsc errors, Python scripts use unsafe shell-style string substitution in one place, and there is no input validation / path-traversal defense in the build CLIs (acceptable as developer-only tools, but worth noting).


Security Findings

1. Initial Security Analysis

  • N/A for most categories: no authentication, authorization, session, database, or user-facing endpoints. This is a build-time library consumed at dev time in derived projects.
  • Medium — bin/fetch-openapi.sh embeds $OUT path directly inside a heredoc passed to python3 -c. If OPENAPI_OUT were attacker-controlled (it is not in practice — it's a dev env var), it would allow Python code injection via quote-breaking in the filename. Fix: pass $OUT via sys.argv rather than f-string substitution in the script heredoc.
    • bin/fetch-openapi.sh:32-37
  • Low — curl -fsS "$URL" with no pinned CA or fingerprint. URL defaults to http://127.0.0.1, so not an issue by default, but documented support for OPENAPI_URL=https://… gives no transport-security hardening. Fine for dev, note in README.
  • Dependency surface is minimal: peer deps (vite, @vitejs/plugin-react, react), devDeps (typescript, @types/node, @types/react). package-lock.json is 60 KB — routine.
  • N/A. No session or cookie handling.
  • src/core-fetch.ts always sets credentials: 'include', which is correct for derived SPAs that talk to a same-origin oatpp backend. No cookie parsing happens here.

3. Authentication Flow Review

  • N/A. No authentication code. core-fetch.ts merely forwards credentials and exposes an on401 hook so consumers can redirect to a login page. The hook contract is fine: on401 is a side-effect callback; the error is still thrown unless the non-OK branch is taken — which it will be for 401 since r.ok is false and no special swallow exists. Consumers relying on on401 should NOT assume the error is swallowed.

4. Input Validation (SQLi / XSS / injection)

  • N/A for SQLi/XSS — no DB, no HTML rendering.
  • Medium — bin/inject-hashed-filenames.py performs a naïve html.replace(old_src, new_src). If old_src ever occurred as a substring outside a <script src="…"> attribute in an HTML file (e.g. inside a comment or another tag), it would be rewritten unexpectedly. Safer: parse the HTML or match on the full tag. Low exploitability since it operates on project-controlled static files, but it's a latent bug.
    • bin/inject-hashed-filenames.py:50-52
  • Low — bin/postprocess-openapi.py trusts openapi.json structure. pathsmethods iteration assumes dicts; malformed input will AttributeError with an unhelpful message. Acceptable for a dev script but the bundled isinstance(op, dict) guard only covers op, not methods.
    • bin/postprocess-openapi.py:39-44
  • createCoreFetch does not sanitise url before concatenating with baseUrl. Relative-URL or absolute-URL bypass of the baseUrl prefix is trivial (an url starting with http://evil will be sent to evil since ${base}${url} just concatenates). This matches fetch semantics and Orval-generated callsites always pass server-emitted paths, but document it.
    • src/core-fetch.ts:136

5. Authorization Implementation

  • N/A. No authorization logic.

6. Database Security

  • N/A. No database.

7. Secrets Management

  • bin/fetch-openapi.sh reads APP_API_KEY from env and passes it as a Bearer token. Key is not logged (only URL → OUT is echoed). Acceptable.
  • No secrets are stored in-tree. No .env files. package.json has no embedded tokens. .gitignore is minimal (only 36 bytes — spot-checked; git log shows no history of leaked credentials).
  • Low — ~/.npmrc registry URL is documented in README as unauthenticated HTTP (http://127.0.0.1:3000/api/packages/uwe.admin/npm/). Expected (internal Forgejo), but _authToken handling is left to the consumer — README could remind devs the token lives in ~/.npmrc and must never be committed.

8. Business Logic Vulnerabilities

  • N/A. No business logic — no bookings, no pricing, no Kurtaxe. This is build tooling.

9. API & Infrastructure Security

  • N/A. No API server.
  • createCoreFetch sets X-Requested-With: XMLHttpRequest so the derived oatpp CsrfInterceptor accepts the request. Fine.
  • Low — default response shape is 'wrapped' while the README and fewo convention is 'body'. Mismatch between docs and default could cause a consumer to silently get {data, status, headers} where they expected the body. Consider aligning the default, or calling the mismatch out more loudly in README.
    • src/core-fetch.ts:104 vs README.md:46-62

10. Logging & Monitoring

  • N/A for server-side. Library-side: createCoreFetch swallows failed fetches silently if onNetworkFailure returns a value. Consumers could unknowingly mask systemic outages. Acceptable because the hook is opt-in, but doc it.

11. File Handling & Uploads

  • N/A. No uploads.
  • Low — build CLIs trust paths from config JSON / argv without normalization. inject-hashed-filenames.py does os.path.join(build_dir, e["manifest"]) — a config with "manifest": "../../etc/passwd" would read an arbitrary file. Dev-only tool so the threat is trust-in-your-own-repo level, not a real vulnerability.
    • bin/inject-hashed-filenames.py:66-71

12. Comprehensive Security Report (synthesis of 01–11)

The scaffold has no critical or high security findings. All "applicable" findings are Medium or Low and concentrated in the three build CLIs under bin/. The TypeScript sources (core-fetch, i18n, vite-config) are defensive and well-factored. Top 3 actionable items:

  1. Fix the Python-code-injection shaped pattern in fetch-openapi.sh:32-37 (pass $OUT via argv, not f-string).
  2. Make the HTML rewrite in inject-hashed-filenames.py tag-aware rather than substring-based.
  3. Document the default responseShape: 'wrapped' vs the README's 'body' example, or flip the default.

Code Quality Findings

13. Architecture & Design

  • Clean separation of concerns across four modules: build factories (vite-config), HTTP mutator (core-fetch), i18n (i18n + React binding i18n-react), and codegen CLIs (bin/).
  • package.json exports map is precise — each entry point has its own types/ESM bundle. No accidental re-exports.
  • React peer dep is marked optional and the React binding is split into its own file so non-React consumers don't pay the peer cost. Good.
  • Low — dist/ is listed in files but the prepare script does tsc || true. Publishing with a broken type build would silently ship no dist. Replace with strict tsc and move error tolerance (if desired) to a CI step.
    • package.json:35

14. Code Duplication

  • None material. defineAdminConfig and defineGuestConfig share ~70 % structure; extraction into defineViteConfig(common) would save ~15 lines but costs clarity. Current duplication is acceptable at this size.
  • The Python CLIs do not duplicate each other.

15. Error Handling

  • src/core-fetch.ts has consistent error branches: network failure → hook → rethrow; 401 → hook → continue; 409 → hook → swallow-or-throw with decorate409; other !ok → formatError hook → throw. Flow is clear and documented.
  • Medium — core-fetch.ts 204 + non-JSON content-type path returns await r.text() as the parsed body. A non-application/json 200 OK will silently return the raw text where the caller's generated type expects an object. This matches no Orval response type. Prefer erroring on unexpected content-type, or at least documenting.
    • src/core-fetch.ts:175-178
  • readBody() catches both .json() and .text() failures and returns ['', null]. Reasonable for test-mock resilience; ensure a comment captures the tradeoff (it already does).

16. Exception Flow Analysis

  • Only core-fetch.ts throws. Other modules are pure data. createI18n never throws; missing keys log via onMiss and return the raw key — correct for UX.
  • The 401 branch does NOT swallow the error (only runs the hook, then falls through to !r.ok, which throws). Callers depending on the hook to redirect-and-never-return will still see a thrown rejection. Document explicitly.

17. Code Quality Metrics

  • Total: 749 LOC across 8 files. Max file size: core-fetch.ts at 214 lines. Largest function: coreFetch closure at ~65 lines. Cyclomatic complexity is low everywhere; no file warrants splitting.
  • No dead code spotted.

18. Design Patterns

  • Factory pattern (createCoreFetch, createI18n, defineAdminConfig) used appropriately — returns closures with captured config. No globals.
  • Observer pattern in createI18n (listeners + subscribe) integrates correctly with React's useSyncExternalStore. Good.
  • No misuse spotted.

19. SOLID Principles

  • S: each module has one reason to change.
  • O: createCoreFetch is open via hook options; closed for modification.
  • L/I: N/A for this style.
  • D: fetchImpl injection in createCoreFetch allows test-time substitution — canonical DIP.

20. Testing Implementation

  • Medium — no tests whatsoever. Repo has no test/, tests/, spec/, __tests__/, no vitest/jest config, no npm test script. The fetchImpl injection point exists specifically for testing but is never exercised inside the scaffold itself. Given the library is consumed by multiple projects, unit tests for createCoreFetch (response shapes, 401/409 hooks, network-failure hook, enqueue short-circuit) and createI18n (resolver chain, tone fallback, miss logging, subscribe/notify) would be high-leverage.

21. Readability & Naming

  • JSDoc is thorough on public types (CoreFetchOptions, I18nOptions). Inline comments explain the why (e.g. why fetchImpl resolves lazily; why .json() is tried before .clone()).
  • Names are consistent and descriptive. MUTATING constant is clear. chain() in i18n.ts is a touch cryptic — consider resolveLookupOrder(). Minor.

22. Resilience & Fault Tolerance

  • onNetworkFailure hook is the single resilience seam and is well-designed (synthetic 0-status wrap mirrors real responses).
  • No retry/backoff built in — correct for a low-level mutator (consumers own retry policy).
  • createI18n is pure and deterministic — no fault surface.

23. Orval Codegen Duplication

  • N/A. This repo IS the mutator — it does not consume the generated client. No hand-rolled fetches to flag.

Prioritized Remediation Plan

  • [MEDIUM] Pass $OUT to the embedded Python via sys.argv, not f-string substitution, to close the injection-shaped pattern — bin/fetch-openapi.sh:32-37
  • [MEDIUM] Replace substring html.replace(old_src, new_src) with tag-aware rewrite (regex on <script src="…"> or a tiny HTML parser) — bin/inject-hashed-filenames.py:50-52
  • [MEDIUM] Add a vitest suite for createCoreFetch (each hook, each response shape, 401/409/network paths) and createI18n (resolver chain, miss cache, subscribe/notify). Wire npm test into prepare
  • [MEDIUM] Decide on default responseShape: either flip to 'body' to match the README example or update README and every derived project's call site to pass responseShape: 'body' explicitly — src/core-fetch.ts:104
  • [LOW] Remove || true from the prepare script so a broken tsc fails the publish — package.json:35
  • [LOW] Document that on401 does NOT swallow the error — callers must still .catch() or rely on the navigation to unmount — src/core-fetch.ts:151 + README
  • [LOW] Error (or at minimum warn) on unexpected non-JSON 2xx bodies in core-fetch rather than silently returning text — src/core-fetch.ts:175-178
  • [LOW] Harden postprocess-openapi.py against malformed paths values (isinstance(methods, dict) guard, helpful error) — bin/postprocess-openapi.py:39-44
  • [LOW] Normalize / confine paths read from the config JSON in inject-hashed-filenames.py to build_dir to defend against ../ traversal even from a trusted config — bin/inject-hashed-filenames.py:66-71
  • [LOW] README: add a note about ~/.npmrc auth-token hygiene and call out that registry URL is plain HTTP (localhost-only) — README.md:25-29
## Code Audit Report — 2026-04-23 Automated audit of `webapp-scaffold` covering 23 audit categories. `webapp-scaffold` is a small (~750 LOC, 8 source files) shared npm library (`@uschuster/webapp-scaffold`) providing frontend build glue for derived projects: Vite config factories, an Orval `fetch` mutator (`createCoreFetch`), a tiny i18n store, and three codegen/build CLIs (`fetch-openapi.sh`, `postprocess-openapi.py`, `inject-hashed-filenames.py`). It is **not** an application: no Oat++ backend, no SQLite, no authentication, no controllers, no user input handling, no file uploads, no server-side logging, no tests. Most of the 23 prompts target application concerns that simply do not exist here; findings reflect what is present. ### Executive Summary - Critical: 0 - High: 0 - Medium: 3 - Low: 6 - Informational / N/A: 12 audits do not apply (no backend / DB / auth / etc.) The scaffold is small, focused, well-commented, and has no obvious security issues in its own code. The main gaps are **library hygiene**: no tests, `prepare` script swallows `tsc` errors, Python scripts use unsafe shell-style string substitution in one place, and there is no input validation / path-traversal defense in the build CLIs (acceptable as developer-only tools, but worth noting). --- ### Security Findings #### 1. Initial Security Analysis - **N/A** for most categories: no authentication, authorization, session, database, or user-facing endpoints. This is a build-time library consumed at dev time in derived projects. - **Medium — `bin/fetch-openapi.sh` embeds `$OUT` path directly inside a heredoc passed to `python3 -c`.** If `OPENAPI_OUT` were attacker-controlled (it is not in practice — it's a dev env var), it would allow Python code injection via quote-breaking in the filename. Fix: pass `$OUT` via `sys.argv` rather than f-string substitution in the script heredoc. - `bin/fetch-openapi.sh:32-37` - **Low — `curl -fsS "$URL"` with no pinned CA or fingerprint.** URL defaults to `http://127.0.0.1`, so not an issue by default, but documented support for `OPENAPI_URL=https://…` gives no transport-security hardening. Fine for dev, note in README. - Dependency surface is minimal: peer deps (`vite`, `@vitejs/plugin-react`, `react`), devDeps (`typescript`, `@types/node`, `@types/react`). `package-lock.json` is 60 KB — routine. #### 2. Session & Cookie Security - **N/A.** No session or cookie handling. - `src/core-fetch.ts` always sets `credentials: 'include'`, which is correct for derived SPAs that talk to a same-origin oatpp backend. No cookie parsing happens here. #### 3. Authentication Flow Review - **N/A.** No authentication code. `core-fetch.ts` merely forwards credentials and exposes an `on401` hook so consumers can redirect to a login page. The hook contract is fine: `on401` is a side-effect callback; the error is still thrown unless the non-OK branch is taken — which it will be for 401 since `r.ok` is false and no special swallow exists. Consumers relying on `on401` should NOT assume the error is swallowed. #### 4. Input Validation (SQLi / XSS / injection) - **N/A for SQLi/XSS** — no DB, no HTML rendering. - **Medium — `bin/inject-hashed-filenames.py` performs a naïve `html.replace(old_src, new_src)`.** If `old_src` ever occurred as a substring outside a `<script src="…">` attribute in an HTML file (e.g. inside a comment or another tag), it would be rewritten unexpectedly. Safer: parse the HTML or match on the full tag. Low exploitability since it operates on project-controlled static files, but it's a latent bug. - `bin/inject-hashed-filenames.py:50-52` - **Low — `bin/postprocess-openapi.py` trusts `openapi.json` structure.** `paths` → `methods` iteration assumes dicts; malformed input will `AttributeError` with an unhelpful message. Acceptable for a dev script but the bundled `isinstance(op, dict)` guard only covers `op`, not `methods`. - `bin/postprocess-openapi.py:39-44` - `createCoreFetch` does not sanitise `url` before concatenating with `baseUrl`. Relative-URL or absolute-URL bypass of the baseUrl prefix is trivial (an `url` starting with `http://evil` will be sent to `evil` since `${base}${url}` just concatenates). This matches `fetch` semantics and Orval-generated callsites always pass server-emitted paths, but document it. - `src/core-fetch.ts:136` #### 5. Authorization Implementation - **N/A.** No authorization logic. #### 6. Database Security - **N/A.** No database. #### 7. Secrets Management - `bin/fetch-openapi.sh` reads `APP_API_KEY` from env and passes it as a Bearer token. Key is not logged (only `URL → OUT` is echoed). Acceptable. - No secrets are stored in-tree. No `.env` files. `package.json` has no embedded tokens. `.gitignore` is minimal (only 36 bytes — spot-checked; git log shows no history of leaked credentials). - **Low — `~/.npmrc` registry URL is documented in README as unauthenticated HTTP (`http://127.0.0.1:3000/api/packages/uwe.admin/npm/`).** Expected (internal Forgejo), but `_authToken` handling is left to the consumer — README could remind devs the token lives in `~/.npmrc` and must never be committed. #### 8. Business Logic Vulnerabilities - **N/A.** No business logic — no bookings, no pricing, no Kurtaxe. This is build tooling. #### 9. API & Infrastructure Security - **N/A.** No API server. - `createCoreFetch` sets `X-Requested-With: XMLHttpRequest` so the derived oatpp `CsrfInterceptor` accepts the request. Fine. - **Low — default response shape is `'wrapped'`** while the README and fewo convention is `'body'`. Mismatch between docs and default could cause a consumer to silently get `{data, status, headers}` where they expected the body. Consider aligning the default, or calling the mismatch out more loudly in README. - `src/core-fetch.ts:104` vs `README.md:46-62` #### 10. Logging & Monitoring - **N/A for server-side.** Library-side: `createCoreFetch` swallows failed fetches silently if `onNetworkFailure` returns a value. Consumers could unknowingly mask systemic outages. Acceptable because the hook is opt-in, but doc it. #### 11. File Handling & Uploads - **N/A.** No uploads. - **Low — build CLIs trust paths from config JSON / argv without normalization.** `inject-hashed-filenames.py` does `os.path.join(build_dir, e["manifest"])` — a config with `"manifest": "../../etc/passwd"` would read an arbitrary file. Dev-only tool so the threat is trust-in-your-own-repo level, not a real vulnerability. - `bin/inject-hashed-filenames.py:66-71` #### 12. Comprehensive Security Report (synthesis of 01–11) The scaffold has **no critical or high security findings**. All "applicable" findings are Medium or Low and concentrated in the three build CLIs under `bin/`. The TypeScript sources (`core-fetch`, `i18n`, `vite-config`) are defensive and well-factored. Top 3 actionable items: 1. Fix the Python-code-injection shaped pattern in `fetch-openapi.sh:32-37` (pass `$OUT` via argv, not f-string). 2. Make the HTML rewrite in `inject-hashed-filenames.py` tag-aware rather than substring-based. 3. Document the default `responseShape: 'wrapped'` vs the README's `'body'` example, or flip the default. --- ### Code Quality Findings #### 13. Architecture & Design - Clean separation of concerns across four modules: build factories (`vite-config`), HTTP mutator (`core-fetch`), i18n (`i18n` + React binding `i18n-react`), and codegen CLIs (`bin/`). - `package.json` `exports` map is precise — each entry point has its own types/ESM bundle. No accidental re-exports. - React peer dep is marked optional and the React binding is split into its own file so non-React consumers don't pay the peer cost. Good. - **Low — `dist/` is listed in `files` but the `prepare` script does `tsc || true`.** Publishing with a broken type build would silently ship no dist. Replace with strict `tsc` and move error tolerance (if desired) to a CI step. - `package.json:35` #### 14. Code Duplication - **None material.** `defineAdminConfig` and `defineGuestConfig` share ~70 % structure; extraction into `defineViteConfig(common)` would save ~15 lines but costs clarity. Current duplication is acceptable at this size. - The Python CLIs do not duplicate each other. #### 15. Error Handling - `src/core-fetch.ts` has consistent error branches: network failure → hook → rethrow; 401 → hook → continue; 409 → hook → swallow-or-throw with `decorate409`; other !ok → `formatError` hook → throw. Flow is clear and documented. - **Medium — `core-fetch.ts` 204 + non-JSON content-type path returns `await r.text()` as the parsed body.** A non-`application/json` `200 OK` will silently return the raw text where the caller's generated type expects an object. This matches no Orval response type. Prefer erroring on unexpected content-type, or at least documenting. - `src/core-fetch.ts:175-178` - `readBody()` catches both `.json()` and `.text()` failures and returns `['', null]`. Reasonable for test-mock resilience; ensure a comment captures the tradeoff (it already does). #### 16. Exception Flow Analysis - Only `core-fetch.ts` throws. Other modules are pure data. `createI18n` never throws; missing keys log via `onMiss` and return the raw key — correct for UX. - The 401 branch does NOT swallow the error (only runs the hook, then falls through to `!r.ok`, which throws). Callers depending on the hook to redirect-and-never-return will still see a thrown rejection. Document explicitly. #### 17. Code Quality Metrics - Total: 749 LOC across 8 files. Max file size: `core-fetch.ts` at 214 lines. Largest function: `coreFetch` closure at ~65 lines. Cyclomatic complexity is low everywhere; no file warrants splitting. - No dead code spotted. #### 18. Design Patterns - Factory pattern (`createCoreFetch`, `createI18n`, `defineAdminConfig`) used appropriately — returns closures with captured config. No globals. - Observer pattern in `createI18n` (`listeners` + `subscribe`) integrates correctly with React's `useSyncExternalStore`. Good. - No misuse spotted. #### 19. SOLID Principles - **S:** each module has one reason to change. - **O:** `createCoreFetch` is open via hook options; closed for modification. - **L/I:** N/A for this style. - **D:** `fetchImpl` injection in `createCoreFetch` allows test-time substitution — canonical DIP. #### 20. Testing Implementation - **Medium — no tests whatsoever.** Repo has no `test/`, `tests/`, `spec/`, `__tests__/`, no vitest/jest config, no `npm test` script. The `fetchImpl` injection point exists specifically for testing but is never exercised inside the scaffold itself. Given the library is consumed by multiple projects, unit tests for `createCoreFetch` (response shapes, 401/409 hooks, network-failure hook, enqueue short-circuit) and `createI18n` (resolver chain, tone fallback, miss logging, subscribe/notify) would be high-leverage. #### 21. Readability & Naming - JSDoc is thorough on public types (`CoreFetchOptions`, `I18nOptions`). Inline comments explain the *why* (e.g. why `fetchImpl` resolves lazily; why `.json()` is tried before `.clone()`). - Names are consistent and descriptive. `MUTATING` constant is clear. `chain()` in `i18n.ts` is a touch cryptic — consider `resolveLookupOrder()`. Minor. #### 22. Resilience & Fault Tolerance - `onNetworkFailure` hook is the single resilience seam and is well-designed (synthetic 0-status wrap mirrors real responses). - No retry/backoff built in — correct for a low-level mutator (consumers own retry policy). - `createI18n` is pure and deterministic — no fault surface. #### 23. Orval Codegen Duplication - **N/A.** This repo IS the mutator — it does not consume the generated client. No hand-rolled fetches to flag. --- ### Prioritized Remediation Plan - [ ] **[MEDIUM]** Pass `$OUT` to the embedded Python via `sys.argv`, not f-string substitution, to close the injection-shaped pattern — `bin/fetch-openapi.sh:32-37` - [ ] **[MEDIUM]** Replace substring `html.replace(old_src, new_src)` with tag-aware rewrite (regex on `<script src="…">` or a tiny HTML parser) — `bin/inject-hashed-filenames.py:50-52` - [ ] **[MEDIUM]** Add a vitest suite for `createCoreFetch` (each hook, each response shape, 401/409/network paths) and `createI18n` (resolver chain, miss cache, subscribe/notify). Wire `npm test` into `prepare` - [ ] **[MEDIUM]** Decide on default `responseShape`: either flip to `'body'` to match the README example or update README and every derived project's call site to pass `responseShape: 'body'` explicitly — `src/core-fetch.ts:104` - [ ] **[LOW]** Remove `|| true` from the `prepare` script so a broken `tsc` fails the publish — `package.json:35` - [ ] **[LOW]** Document that `on401` does NOT swallow the error — callers must still `.catch()` or rely on the navigation to unmount — `src/core-fetch.ts:151` + README - [ ] **[LOW]** Error (or at minimum warn) on unexpected non-JSON 2xx bodies in `core-fetch` rather than silently returning text — `src/core-fetch.ts:175-178` - [ ] **[LOW]** Harden `postprocess-openapi.py` against malformed `paths` values (`isinstance(methods, dict)` guard, helpful error) — `bin/postprocess-openapi.py:39-44` - [ ] **[LOW]** Normalize / confine paths read from the config JSON in `inject-hashed-filenames.py` to `build_dir` to defend against `../` traversal even from a trusted config — `bin/inject-hashed-filenames.py:66-71` - [ ] **[LOW]** README: add a note about `~/.npmrc` auth-token hygiene and call out that registry URL is plain HTTP (localhost-only) — `README.md:25-29`
Author
Owner

Agent Evaluation

This issue is a code audit report (filed by the /code-audit skill), not a feature request. No evaluation action needed from the poll loop — each line in the Prioritized Remediation Plan is itself a checkbox that can be split into discrete fix issues by the owner on demand.

Feasibility: N/A — tracking issue.
Impact: Informational; owner triages findings.
Effort: N/A (individual fixes range small-to-medium).
Recommendation: Leave open as an index; close once all prioritized checkboxes are addressed or split into child issues.

Labeling evaluated + effort:medium so the loop skips it on future passes.

## Agent Evaluation This issue is a **code audit report** (filed by the /code-audit skill), not a feature request. No evaluation action needed from the poll loop — each line in the _Prioritized Remediation Plan_ is itself a checkbox that can be split into discrete fix issues by the owner on demand. **Feasibility:** N/A — tracking issue. **Impact:** Informational; owner triages findings. **Effort:** N/A (individual fixes range small-to-medium). **Recommendation:** Leave open as an index; close once all prioritized checkboxes are addressed or split into child issues. Labeling `evaluated` + `effort:medium` so the loop skips it on future passes.
uwe.admin added the
effort:medium
evaluated
labels 2026-04-23 12:00:27 +02:00
Author
Owner

Evaluated #1 — code audit tracking issue, labeled evaluated+effort:medium to exclude from future poll cycles.

Evaluated #1 — code audit tracking issue, labeled evaluated+effort:medium to exclude from future poll cycles.
Author
Owner

Poll cycle: nothing actionable — audit tracker remains the only open issue.

Poll cycle: nothing actionable — audit tracker remains the only open issue.

Split into child issues, please.

Split into child issues, please.
Author
Owner

Re-evaluation

Split into child issues, please.

Done. Filed one child issue per MEDIUM finding so they can be evaluated, prioritised, and accepted independently:

  • #2 — fetch-openapi.sh: pass $OUT via sys.argv, not f-string in heredoc
  • #3 — inject-hashed-filenames.py: tag-aware HTML rewrite instead of substring replace
  • #4 — Add vitest suite for createCoreFetch + createI18n; wire into prepare
  • #5 — Decide createCoreFetch default responseShape and align README + derived projects

The LOW findings I left in this tracker rather than spinning up six more issues — they're docstring/hardening tweaks the next pass over each file can clean up alongside the MEDIUM in that same area. If you'd like them split too, say the word.

This issue stays open as the audit index — close once #2–#5 (and the LOW items inline) are resolved.

## Re-evaluation > Split into child issues, please. Done. Filed one child issue per MEDIUM finding so they can be evaluated, prioritised, and accepted independently: - [ ] #2 — fetch-openapi.sh: pass `$OUT` via `sys.argv`, not f-string in heredoc - [ ] #3 — inject-hashed-filenames.py: tag-aware HTML rewrite instead of substring replace - [ ] #4 — Add vitest suite for `createCoreFetch` + `createI18n`; wire into `prepare` - [ ] #5 — Decide `createCoreFetch` default `responseShape` and align README + derived projects The LOW findings I left in this tracker rather than spinning up six more issues — they're docstring/hardening tweaks the next pass over each file can clean up alongside the MEDIUM in that same area. If you'd like them split too, say the word. This issue stays open as the audit index — close once #2–#5 (and the LOW items inline) are resolved.
Author
Owner

Re-evaluated #1 — split MEDIUM findings into child issues #2/#3/#4/#5 per owner request; LOW items remain inline in tracker.

Re-evaluated #1 — split MEDIUM findings into child issues #2/#3/#4/#5 per owner request; LOW items remain inline in tracker.
uwe.admin added the
accepted
label 2026-04-25 21:32:07 +02:00
Author
Owner

Tracker status

All child issues now closed; closing this tracker.

  • #2 fetch-openapi.sh sys.argv fix → closed
  • #3 inject-hashed-filenames tag-aware regex → closed
  • #4 vitest suite for createCoreFetch + createI18n → closed (owner-implemented)
  • #5 createCoreFetch default responseShape → closed
  • #6 VITE_BASE / loadEnv fix → closed (b1a13b8, v0.3.6)
  • #7 tests/e2e/ password-setup → closed (5ee6894)

Any further audit follow-ups can be filed as fresh issues.

## Tracker status All child issues now closed; closing this tracker. - #2 fetch-openapi.sh sys.argv fix → closed - #3 inject-hashed-filenames tag-aware regex → closed - #4 vitest suite for createCoreFetch + createI18n → closed (owner-implemented) - #5 createCoreFetch default responseShape → closed - #6 VITE_BASE / loadEnv fix → closed (b1a13b8, v0.3.6) - #7 tests/e2e/ password-setup → closed (5ee6894) Any further audit follow-ups can be filed as fresh issues.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: uwe.admin/webapp-scaffold#1
No description provided.