Fix medium-severity issues from follow-up security audit

Addresses the remaining medium findings from the second-pass audit:

- DoS hardening: bound GraphQL query cost with FixedComplexityLimit, and
  reject non-positive items-per-page / page values so uint64 conversion
  cannot underflow into an unbounded LIMIT/OFFSET. The -1 "load all"
  sentinel stays valid for dashboards; REST now returns 400 for bad input.

- Security headers: add X-Content-Type-Options, X-Frame-Options,
  Referrer-Policy and a conservative CSP (frame-ancestors/object-src/
  base-uri) that hardens against clickjacking and base-tag injection
  without restricting the self-hosted SPA's inline scripts.

- Stored XSS: render job.metaData.message as escaped text instead of
  {@html ...} in Job.root and JobFootprint, preserving line breaks via
  white-space: pre-wrap.

- SQL injection hardening: parameterize the tag-scope IN list and the
  manager project subquery in CountTags instead of interpolating
  user.Username / user.Projects (externally sourced via OIDC/LDAP).

- CSRF defense-in-depth: reject cross-site state-changing requests via
  Sec-Fetch-Site, failing open for non-browser clients, on top of the
  existing SameSite=Lax session cookie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: de7d47a85c7c
This commit is contained in:
2026-06-04 20:08:41 +02:00
parent 6d86690c76
commit 16942f55a0
6 changed files with 75 additions and 15 deletions

View File

@@ -237,7 +237,7 @@
The following note was added by administrators:
</Card>
<Card body>
{@html thisJob.metaData.message}
<span style="white-space: pre-wrap">{thisJob.metaData.message}</span>
</Card>
</CardBody>
</TabPane>

View File

@@ -228,7 +228,7 @@
{/each}
{#if job?.metaData?.message}
<hr class="mt-1 mb-2" />
{@html job.metaData.message}
<span style="white-space: pre-wrap">{job.metaData.message}</span>
{/if}
</CardBody>
</Card>