- tainted-filename: filenames in upload_attachment.php and user_avatar.php
are derived exclusively from (int)-cast integers; no user string reaches
the filesystem path. Semgrep's taint engine tracks all use-sites of the
variable, producing findings on every file_exists/readfile/unlink call.
- tainted-callable: index.php audit-log query passes \$sql to prepare();
\$sql is assembled from hardcoded SQL fragments with ? placeholders and
explicit (int) LIMIT/OFFSET casts. User values are bound via bind_param,
never interpolated. Semgrep cannot see through the WHERE-builder logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- index.php: replace SQL string interpolation with concatenation + explicit
(int) casts for LIMIT/OFFSET; add nosemgrep for tainted-sql false positive
(WHERE clause built from hardcoded fragments with bound params only)
- api/upload_attachment.php: add realpath() path-traversal guard after mkdir
- api/user_avatar.php: make (int) cast explicit at cache-path construction;
add nosemgrep for tainted-filename false positive (integer-only input)
- assets/js/ticket.js: add nosemgrep for insertAdjacentHTML — all dynamic
content already escaped via lt.escHtml() before insertion
- .gitea/workflows/security.yml: exclude echoed-request rule globally —
all echo in API context is json_encode() output, not HTML; htmlentities()
fix semgrep suggests would corrupt JSON responses
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- lint.yml: add notify-failure Matrix alert job; add Tag deployed commit
step (main branch only) with deploy-YYYY.MM.DD-N tagging via Gitea API;
add permissions: contents: write to deploy job
- security.yml: new workflow running semgrep with p/php and p/owasp-top-ten
configs on push, PR, and weekly schedule
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a deploy job that runs only when both php-lint and js-lint succeed.
Calls the CT132 webhook directly with HMAC-SHA256 signature from the
WEBHOOK_SECRET repo secret. Disabled the direct push webhooks that
previously deployed on every push regardless of lint status.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>