Feature-scoped security review (single-feature security audit)
For the-platform project: a microservices CRM platform that processes
customer personal data. Security is a critical priority, not a formality.
The audit must find real, exploitable problems tied to file:line, not
produce a generic checklist without verification. Every finding must be
confirmed by hand, not merely mentioned in a scanner's output.
This is the focused version of the full repository audit (see the
security-audit-full skill if the task is the whole repository rather than
a single feature). The verification principles are the same, but the scope,
findings, and report are strictly limited to the code that belongs to this
feature and to what it touches. The manual-analysis work can be delegated
through the Agent tool — use parallelization by zone as described in the
"Running the check" section below.
INPUT: HOW TO DETERMINE THE FEATURE
Feature: $ARGUMENTS
The feature is passed in one of three forms — figure out which one you have
and build the review scope accordingly. The scope is ALWAYS wider than the
literal input: include direct consumers/calling code (the router that
registers the handler; the frontend that hits the API; the neighboring
service that receives the inter-service call).
A. DIRECTORY/BRANCH/DIFF (e.g. services/xxx-service/feature_y/ or
"diff between dev and the feature/PROJ-XXXX branch"):
- Scope = the entire contents of the directory (or the files from
git diff --stat against the base branch) + modules that import it
(grep -r on the package/module name outside the directory) + the
routes/DI that register it (main.py/app factory/router include).
- If the directory is a shared library (libs/shared_auth,
libs/shared_metrics, etc.), be sure to identify ALL consumers of the
library across all services — a vulnerability in shared code multiplies
across the whole list of consumers.
B. DOCUMENT (path to a spec/design document/PRD, .md/.txt/.docx):
- Read the document in full. Extract from it: endpoint/route names,
model/table names, roles and permissions, UI component/screen names, and
any mentioned external integrations (webhooks, callback URLs, third-party
APIs).
- For each extracted term,
grep/search the codebase to translate the
"what should exist" description into concrete file:line "what actually
exists". Do not settle for the document saying something is "implemented"
— verify the code, not the document text.
- If the document describes intent rather than fact (a draft spec), flag
explicitly in the report which items have no counterpart in the code
(this is a finding too: a mismatch between spec and implementation may
mean an unfinished access control).
C. YOUTRACK ISSUE (an ID of the form PROJ-XXXX or a link):
- Fetch the issue text (title, description, comments, acceptance criteria)
through whatever tracker-integration mechanism the project provides (a
YouTrack/Jira/GitHub/Linear MCP tool, if connected). If no programmatic
access exists, ask the user directly for the issue text and links to
related PRs — do not invent the content.
- Find related commits and files by ticket ID: commits in this repository
are conventionally tagged with the ticket number in the message (e.g.
PROJ-1042, PROJ-1031, PROJ-318) — use git log --all --grep=<ISSUE-ID> --oneline, then git show --stat <hash> / git log --all -- <files from commit> to build the list of affected files and
services.
- If the ticket references a PR/branch, review that branch's diff
specifically (
git diff main...<branch>), not just the final state of
main, so you do not miss intermediate versions if the branch is not yet
merged.
If none of the three sources determines the scope unambiguously, stop and
explicitly list what needs to be clarified with the task author, rather than
blindly reviewing the entire service.
Explicitly record at the top of the report the final scope (the list of
files/directories/services) that resulted from this step — this is your
working SCOPE, and the rest of the audit runs on it, plus the points of
contact with the rest of the system (see PASS 3 below).
KEY PRINCIPLE: VERIFICATION, NOT TRUST
The reason feature checks fail is taking it on faith that "the code was
written to spec" is equivalent to "the feature is secure". It is NOT.
Verify adversarially:
- If the feature adds a check (a flag, an HMAC signature, escaping,
authorization), make sure it is ENABLED by default and active in all
environments (dev/staging/prod), not merely implemented in code and
turned off by a flag.
- If the feature adds input escaping, verify COMPLETENESS (single quote,
double quote, backslash, null byte, unicode bypass), not just the
obvious case.
- If the feature protects one endpoint/service, check whether it has
"siblings" of the same class of operation elsewhere in the codebase that
were left unprotected (e.g. the feature added auth on POST but not on
DELETE of the same resource, or on an analogous bulk endpoint).
- If the feature has RBAC/switch/if-else on roles, check the "else" branch
(default case). The absence of an explicit access denial by default is a
hole.
- Do not accept the ticket/spec description ("this is already protected",
"it uses the shared middleware here") without independently verifying the
current code.
- State the status explicitly: "not implemented" / "implemented on paper
(code exists, no protection)" / "implemented selectively (part of the
class covered)" / "fully implemented" / "new finding outside the
feature's scope".
METHODOLOGY: THREE INDEPENDENT PASSES (within the feature SCOPE)
PASS 1 — Focused automated scanning
- If the feature added new dependencies (a new entry in
requirements/pyproject/package.json), run pip-audit/npm audit focused on
the changed lock file, not on the whole repository.
- semgrep/bandit on the files in SCOPE (injection, ssrf, insecure
deserialization, hardcoded secrets, weak crypto).
- If the feature touches Dockerfile/helm-values/k8s manifests, run checkov/
kube-linter focused on the changed files.
- gitleaks/trufflehog on the feature's diff (
git diff/git log -p on the
affected files and commits) — a secret may have been committed and then
deleted within the same branch.
PASS 2 — Manual line-by-line review of the feature code
Review every file in SCOPE line by line (not diagonally), applying the
category checklist below — only those categories that actually apply to what
the feature does (see the applicability hints before the checklist). For
each finding: file:line, vulnerability type, a concrete exploitation
scenario ("request X with parameter Y yields result Z"), severity, status.
If the SCOPE is large (several services/directories) and the Agent tool is
available, split it into independent zones and use several subagents, one
zone each, so you don't cut corners across the whole volume at once (see
"Running the check" below).
PASS 3 — Points of contact with the rest of the system
Independently of the line-by-line review, answer: how does the feature fit
into the platform's existing security invariants, not just "are there holes
in its own code"?
- Does the feature use the existing authentication/authorization/multi-
tenancy mechanisms, or does it invent its own path that bypasses them (a
new handler that does not go through the shared auth middleware/RBAC
decorator)?
- If the feature adds a new internal endpoint between services, is it
protected by the same shared-secret/mTLS mechanism as the rest of the
/internal/* endpoint class, or is it an exception?
- If the feature adds a new data read/write point, is it filtered by
company_id/tenant_id the same way as the other points of the same type in
the system?
- If the feature reuses a shared library (libs/shared_auth, etc.), does it
use the current version as a single package, or did it copy/fork the logic
into itself?
- Does the feature break any of the existing security invariants documented
in previous repository audits? In this project that is not an abstract
caveat — the registry of past findings lives in
docs/bugs/security_audit/ (each past-audit finding records a verdict:
confirmed / false positive / already fixed), and the regression check over
it is scripts/verify_audit_fixes.py. If the feature SCOPE overlaps by
topic or by files with one of the findings in that folder, be sure to run
the script (if present in the repository) and explicitly reconcile the
current status, rather than reopening the finding from scratch.
- If a feature finding effectively coincides with a risk already tracked in
docs/bugs/security_audit/ that was deliberately accepted (a low replica
count for HA, a disabled networkPolicy, etc.), reference the existing
finding file instead of raising a duplicate as a "new feature finding";
note it only if the feature makes the risk worse than it was recorded.
CATEGORY CHECKLIST (apply the ones relevant to the feature)
Before the review, quickly classify the feature: which of the blocks below
apply (a new API endpoint → blocks 1,2,5,6,10; a new UI screen → blocks 1,7;
file upload → block 9; integration/webhook → blocks 4,6,8; infrastructure
change → blocks 11,12). Do not skip a block just because "the feature is
small" — small features are typically exactly the source of pinpoint holes
(see "Edge cases" below).
Authentication and authorization
- Does the new/changed endpoint require authentication the same way as
the other endpoints of the same service (is there a "forgotten" open
route)?
- RBAC branches: what happens for a role that falls into no explicit
branch (default/else)? Does this lead to a leak (no filter by
assigned_user_id/owner_id)?
- IDOR/BOLA: can you access someone else's object that the feature
operates on by changing an ID in the URL/body?
- Broken function level authorization: is the new administrative/bulk
operation accessible without a role check?
- Mass assignment/over-posting: does the new/changed API accept arbitrary
request-body fields (role, is_admin, company_id, balance, etc.), or is
the list of allowed fields an explicit whitelist?
- Session/token: if the feature touches sessions/tokens — where is the
storage, is there invalidation, is there a lifetime limit?
- Rate limiting: if the feature adds a login/password reset/OTP-like flow
— is there a limit on attempts?
Multi-tenancy (isolation between customer companies) — review this
separately from generic IDOR; a cross-tenant leak is heavier in
consequences.
- Every new read/write point (REST handler, WS subscription, cache key,
search index, queue, export) — is it filtered by company_id/tenant_id
at the DB-query level, not just at the UI/router level?
- Is the company_id match checked by an explicit comparison of the value
from the token/context against the record's company_id, rather than
assumed?
- Shared resources (Redis keys, RabbitMQ queues, file storage) — can a
key/name collide between companies given identical internal IDs?
- A new Alembic migration/DDL: does a new table/column that stores a
specific company's data have
company_id/tenant_id and an index on
it — a structural gap at the schema level cannot be caught by a
line-by-line query review if the column itself is missing.
WebSocket / realtime (if the feature touches a realtime channel)
- Is the token/role/company_id checked at connect AND separately at each
channel/room subscription (join)?
- Can a client subscribe to someone else's channel by supplying/guessing
a room-id/dialog-id/user-id?
- Is broadcast filtered by company_id/role before sending, or does the
server rely on the client "just not being subscribed"?
Internal-API between services (if the feature adds/changes
/internal/*)
- Does it require a shared-secret/mTLS the same way as the other
endpoints of the same class of operation in other services? Is the
secret actually verified (not merely declared in env)?
- Can the new internal endpoint be called directly from outside the
cluster?
Injections (SQL / NoSQL / Command / Template / Deserialization)
- Building queries by concatenation/f-string/format instead of
parameterized queries/ORM — especially in new query parameters
(filters, search, sorting).
- "Manual" escaping — verify completeness (backslash, unicode, nested
quotes).
- Command injection: new subprocess/os.system/exec with user input.
- Insecure deserialization of new data from a queue/webhook/inter-service
call (pickle, yaml.load without SafeLoader, eval/exec).
SSRF (if the feature makes an outbound HTTP request to an external
URL)
- Is there a domain allow-list, blocking of private/internal IP ranges
(169.254.x.x, 10.x, 172.16-31.x, 192.168.x, 127.x, cloud metadata)?
- Is the webhook's signature/origin verified before the system initiates
a response request to a URL from its body?
XSS (including client-side widgets, if the feature is a
frontend/embeddable component)
- innerHTML/dangerouslySetInnerHTML/document.write with untrusted data.
- If the feature is a widget embedded on third-party sites: the
vulnerability is visible to the end users of your platform's customers —
qualify severity accounting for the expanded blast radius.
- Are CSP/clickjacking headers not weakened by the new code?
Secrets and PII handling (if the feature touches
integrations/tokens/PII)
- New secrets in code/configs tracked by git.
- New integration tokens in the DB — plaintext or encrypted?
- Secret masking in new logs — does it work for the new data types the
feature introduced?
File upload and storage (if the feature adds upload/download)
- MIME-type/extension validation (do not trust the client's
Content-Type).
- Size limits, protection against zip bombs.
- Path traversal when building a path from user input.
- Public serving — does it require authentication if the files contain
PII?
Dependencies and supply chain (if the feature added new packages)
- Criticality of new dependencies, whether a safer alternative exists.
- A new internal package — installed from a private index/local path, or
by a bare name that can be substituted from public PyPI/npm (dependency
confusion)?
Docker / containers (if the feature changes the Dockerfile)
- Is USER set (non-root)? Are secrets not passed via ARG/ENV?
Kubernetes / Helm (if the feature changes values/manifests)
- Are networkPolicy/securityContext/resources not weakened by the new
values file relative to the project's existing baseline?
- Secrets via Kubernetes Secrets, not plaintext in values.yaml?
Error handling and observability
- A new broad except that logs and returns None/an empty result without
re-raise — does this mask a failed authorization check as "allowed"?
- Are new security events (failed authorizations, role changes) logged
separately?
- Leakage of internal information through new error messages to the
outside.
CI/CD (if the feature changes the pipeline)
- CI script injection: is unvalidated external input (PR title, branch
name) interpolated directly into a
run: step?
- Does the new security gate actually block the merge, or does it only
print a warning?
EDGE CASES OFTEN MISSED WHEN TESTING A FEATURE
- Functionality protected at the UI level (button hidden) but accessible
directly through the API without a backend check.
- A race condition in "check-then-act" (the role check and the action are
not atomic).
- Behavior for soft-deleted records — are they accessible through a new
endpoint that does not account for the deletion flag?
- The bulk variant of the new feature (bulk endpoint) — often added "quick
and dirty" with weaker-verified authorization than its single-item
counterpart.
- The webhook the feature adds — is the signature/origin verified?
- The feature's feature flag, turned off "temporarily for debugging" and
left off by default in the config.
- dev/staging/prod differences — a fix applied in one helm-values
configuration may be absent in another.
- Data export, if the feature adds it — is authorization on the exported
volume as strict as on ordinary reads?
- An old/duplicate path left behind after the feature's refactoring (e.g.
the old endpoint was not removed, it just stopped being called from the
frontend — it is still reachable and not updated to the new authorization
logic).
SEVERITY SCALE (shared with the full repository audit)
A shared scale is needed so findings are comparable across individual
feature checks and full audits (see security-audit-full).
- Critical: an unauthenticated external attacker achieves full compromise
through this feature (RCE, access to all data of all customer companies,
full authentication bypass).
- High: an authenticated user (including one with a minimal role) gains
access to someone else's data/privileges through this feature — including
cross-tenant access — or an unauthenticated attacker gains access to the
data of one company/one user.
- Medium: requires specific conditions (a race, a particular role, MITM,
social engineering) or is limited to metadata leakage/DoS without data
loss.
- Low: a best-practice violation with no direct exploitation scenario at
the time of the check.
For each finding, state who can exploit it (anonymous / authenticated user /
internal network only) and what is lost (read / write / full compromise).
REPORT FORMAT
- Executive summary (no technical jargon): is the feature secure to
release, what is critical, what is a business/regulatory risk, what to do
first.
- SCOPE — the final list of reviewed files/directories/services (see the
"Input" section above) and an explicit note on what was left OUTSIDE the
SCOPE and why (e.g. "shared library X was not re-reviewed since it did
not change in this feature").
- Feature verdict: "ready to release" / "ready with caveats (see
low/medium)" / "not ready — there are critical/high findings" — in one
phrase at the top of the report.
- Full list of findings: file:line, category (may reference OWASP Top 10 /
OWASP API Security Top 10 / CWE), a concrete exploitation scenario,
severity with justification, status, remediation recommendation.
- A "what was done well" section — strong patterns in the feature's
implementation worth replicating.
- Action plan: what blocks the release now (critical/high), what can be
fixed after release with a ticket (medium/low).
- A "what was not checked" section — coverage limitations (no access to the
prod environment, no ability to run a scanner, etc.), so the absence of
findings does not read as "everything there is clean".
FINDING FORMATTING RULES
Before starting, check whether a report for this same feature already exists
in docs/bugs/security_audit/ (e.g. by its feature-slug or ISSUE-ID from a
previous run of this same skill). If it does, do not start numbering from
zero: continue the existing ID sequence and update the status of already
known findings ("not fixed" → "fixed", etc.), rather than re-raising them as
new.
For each finding, the following are mandatory:
- A stable finding ID (e.g.
SEC-<ISSUE-ID or feature-slug>-001), unique
within the reports for this feature (see above on re-runs).
- The file path and line number (or range).
- The vulnerability name and category (OWASP Top 10 / OWASP API Security Top
10 / CWE).
- A concrete exploitation scenario: "if you make request X with parameter Y,
the system will return/do Z" — not abstract wording like "there may be a
vulnerability".
- Severity with justification (who can use it, what is lost).
- A remediation recommendation — concrete ("add an else branch with an
explicit denial", "enable flag X by default", "replace the f-string with a
parameterized query").
RUNNING THE CHECK (practical instructions)
- First, YOURSELF (in the main thread), do the "Input" section — determine
the input type (directory/branch/diff, document, YouTrack issue) and build
the SCOPE. Do not delegate this step: a subagent starts without the
conversation context and does not know what was meant by "the feature".
Record the SCOPE explicitly before moving to the review.
- Classify the feature by change type (new API, new UI, integration/webhook,
file upload, infrastructure, etc.) and select the applicable checklist
blocks.
- Check whether a report for this feature already exists in
docs/bugs/security_audit/ (see "Finding formatting rules") — this is a
cheap check that saves rework and preserves the continuity of finding
numbering.
- Run the focused automated checks of PASS 1 on the files/dependencies in
SCOPE (semgrep/bandit focused, SCA on the changed lock files, gitleaks on
the feature's diff).
- Perform the manual line-by-line review of PASS 2. If the SCOPE spans
several services/directories and the Agent tool is available, split it
into independent zones and launch a separate subagent per zone (in
foreground, if the result is needed for a further decision in this same
dialogue) so as not to cut corners across the whole volume at once. Give
each subagent the concrete paths and the applicable sections of this skill
(checklist, severity scale, finding format) — a subagent does not see this
file itself. Record confirmed findings in an intermediate file as you
review each zone, rather than keeping them only in context until the final
report.
- Perform PASS 3 — the feature's points of contact with the platform's
existing security invariants (authentication, multi-tenancy, internal-API,
shared libraries).
- Consolidate all three passes into a single report per the format above,
remove duplicates, but do not merge findings of different natures (a
scanner found a pattern ≠ manual review confirmed exploitability — record
both facts if both exist). Save the final report as a file at
docs/bugs/security_audit/<feature-slug>-security-review.md (slug — by
ISSUE-ID or by feature/directory name) — this is the same place where the
registry of past audit findings lives, and the next run of this skill on
the same feature should find and update it, rather than recreating it from
scratch.
- Explicitly state which checks were NOT performed (no access to prod
secrets, no access to runtime logs, no ability to run a scanner, etc.) —
this is part of an honest report, not its weakness.
- If the project has a
security-review skill/agent configured (a quick
review of pending changes on the current branch), you can use it as a
starting point for PASS 2 on the changed files, but do not limit yourself
to the diff: the feature may rely on existing code that did not change in
the current branch but participates in its security model (see PASS 3).
This is testing, not implementation: the developer makes the changes based on
the report, not you within this skill.
1---2name: security-audit-feature3description: Focused security audit of ONE specific feature/change in the-platform (not the whole repository) — scope taken from a directory/branch/diff, a spec/PRD document, or a YouTrack issue; the same verification discipline as the full audit (adversarial verification, three independent passes, a 14-category checklist — auth/authz, multi-tenancy, websocket, internal API, injections, SSRF, XSS, secrets/PII, files, dependencies, docker, k8s/helm, error handling, CI/CD), with findings tied to file:line and an explicit release-readiness verdict. Use when asked to check the security of a specific feature, branch, PR, or YouTrack task before merge/release, to find vulnerabilities in a new endpoint/integration/file upload/webhook, or to assess whether new functionality opens access to someone else's data or another company — even without the word "audit", e.g. "is this feature leaking between companies", "is this feature OK to merge security-wise", "check this branch for security holes". This is NOT the same as the `security4---56# Feature-scoped security review (single-feature security audit)78For the-platform project: a microservices CRM platform that processes9customer personal data. Security is a critical priority, not a formality.10The audit must find real, exploitable problems tied to file:line, not11produce a generic checklist without verification. Every finding must be12confirmed by hand, not merely mentioned in a scanner's output.1314This is the focused version of the full repository audit (see the15`security-audit-full` skill if the task is the whole repository rather than16a single feature). The verification principles are the same, but the scope,17findings, and report are strictly limited to the code that belongs to this18feature and to what it touches. The manual-analysis work can be delegated19through the Agent tool — use parallelization by zone as described in the20"Running the check" section below.2122## INPUT: HOW TO DETERMINE THE FEATURE2324Feature: `$ARGUMENTS`2526The feature is passed in one of three forms — figure out which one you have27and build the review scope accordingly. The scope is ALWAYS wider than the28literal input: include direct consumers/calling code (the router that29registers the handler; the frontend that hits the API; the neighboring30service that receives the inter-service call).3132**A. DIRECTORY/BRANCH/DIFF** (e.g. `services/xxx-service/feature_y/` or33"diff between dev and the feature/PROJ-XXXX branch"):34- Scope = the entire contents of the directory (or the files from35 `git diff --stat` against the base branch) + modules that import it36 (`grep -r` on the package/module name outside the directory) + the37 routes/DI that register it (main.py/app factory/router include).38- If the directory is a shared library (libs/shared_auth,39 libs/shared_metrics, etc.), be sure to identify ALL consumers of the40 library across all services — a vulnerability in shared code multiplies41 across the whole list of consumers.4243**B. DOCUMENT** (path to a spec/design document/PRD, .md/.txt/.docx):44- Read the document in full. Extract from it: endpoint/route names,45 model/table names, roles and permissions, UI component/screen names, and46 any mentioned external integrations (webhooks, callback URLs, third-party47 APIs).48- For each extracted term, `grep`/search the codebase to translate the49 "what should exist" description into concrete file:line "what actually50 exists". Do not settle for the document saying something is "implemented"51 — verify the code, not the document text.52- If the document describes intent rather than fact (a draft spec), flag53 explicitly in the report which items have no counterpart in the code54 (this is a finding too: a mismatch between spec and implementation may55 mean an unfinished access control).5657**C. YOUTRACK ISSUE** (an ID of the form `PROJ-XXXX` or a link):58- Fetch the issue text (title, description, comments, acceptance criteria)59 through whatever tracker-integration mechanism the project provides (a60 YouTrack/Jira/GitHub/Linear MCP tool, if connected). If no programmatic61 access exists, ask the user directly for the issue text and links to62 related PRs — do not invent the content.63- Find related commits and files by ticket ID: commits in this repository64 are conventionally tagged with the ticket number in the message (e.g.65 `PROJ-1042`, `PROJ-1031`, `PROJ-318`) — use `git log --all66 --grep=<ISSUE-ID> --oneline`, then `git show --stat <hash>` / `git log67 --all -- <files from commit>` to build the list of affected files and68 services.69- If the ticket references a PR/branch, review that branch's diff70 specifically (`git diff main...<branch>`), not just the final state of71 main, so you do not miss intermediate versions if the branch is not yet72 merged.7374If none of the three sources determines the scope unambiguously, stop and75explicitly list what needs to be clarified with the task author, rather than76blindly reviewing the entire service.7778Explicitly record at the top of the report the final scope (the list of79files/directories/services) that resulted from this step — this is your80working SCOPE, and the rest of the audit runs on it, plus the points of81contact with the rest of the system (see PASS 3 below).8283## KEY PRINCIPLE: VERIFICATION, NOT TRUST8485The reason feature checks fail is taking it on faith that "the code was86written to spec" is equivalent to "the feature is secure". It is NOT.87Verify adversarially:88891. If the feature adds a check (a flag, an HMAC signature, escaping,90 authorization), make sure it is ENABLED by default and active in all91 environments (dev/staging/prod), not merely implemented in code and92 turned off by a flag.932. If the feature adds input escaping, verify COMPLETENESS (single quote,94 double quote, backslash, null byte, unicode bypass), not just the95 obvious case.963. If the feature protects one endpoint/service, check whether it has97 "siblings" of the same class of operation elsewhere in the codebase that98 were left unprotected (e.g. the feature added auth on POST but not on99 DELETE of the same resource, or on an analogous bulk endpoint).1004. If the feature has RBAC/switch/if-else on roles, check the "else" branch101 (default case). The absence of an explicit access denial by default is a102 hole.1035. Do not accept the ticket/spec description ("this is already protected",104 "it uses the shared middleware here") without independently verifying the105 current code.1066. State the status explicitly: "not implemented" / "implemented on paper107 (code exists, no protection)" / "implemented selectively (part of the108 class covered)" / "fully implemented" / "new finding outside the109 feature's scope".110111## METHODOLOGY: THREE INDEPENDENT PASSES (within the feature SCOPE)112113### PASS 1 — Focused automated scanning114115- If the feature added new dependencies (a new entry in116 requirements/pyproject/package.json), run pip-audit/npm audit focused on117 the changed lock file, not on the whole repository.118- semgrep/bandit on the files in SCOPE (injection, ssrf, insecure119 deserialization, hardcoded secrets, weak crypto).120- If the feature touches Dockerfile/helm-values/k8s manifests, run checkov/121 kube-linter focused on the changed files.122- gitleaks/trufflehog on the feature's diff (`git diff`/`git log -p` on the123 affected files and commits) — a secret may have been committed and then124 deleted within the same branch.125126### PASS 2 — Manual line-by-line review of the feature code127128Review every file in SCOPE line by line (not diagonally), applying the129category checklist below — only those categories that actually apply to what130the feature does (see the applicability hints before the checklist). For131each finding: file:line, vulnerability type, a concrete exploitation132scenario ("request X with parameter Y yields result Z"), severity, status.133134If the SCOPE is large (several services/directories) and the Agent tool is135available, split it into independent zones and use several subagents, one136zone each, so you don't cut corners across the whole volume at once (see137"Running the check" below).138139### PASS 3 — Points of contact with the rest of the system140141Independently of the line-by-line review, answer: how does the feature fit142into the platform's existing security invariants, not just "are there holes143in its own code"?144145- Does the feature use the existing authentication/authorization/multi-146 tenancy mechanisms, or does it invent its own path that bypasses them (a147 new handler that does not go through the shared auth middleware/RBAC148 decorator)?149- If the feature adds a new internal endpoint between services, is it150 protected by the same shared-secret/mTLS mechanism as the rest of the151 `/internal/*` endpoint class, or is it an exception?152- If the feature adds a new data read/write point, is it filtered by153 company_id/tenant_id the same way as the other points of the same type in154 the system?155- If the feature reuses a shared library (libs/shared_auth, etc.), does it156 use the current version as a single package, or did it copy/fork the logic157 into itself?158- Does the feature break any of the existing security invariants documented159 in previous repository audits? In this project that is not an abstract160 caveat — the registry of past findings lives in161 `docs/bugs/security_audit/` (each past-audit finding records a verdict:162 confirmed / false positive / already fixed), and the regression check over163 it is `scripts/verify_audit_fixes.py`. If the feature SCOPE overlaps by164 topic or by files with one of the findings in that folder, be sure to run165 the script (if present in the repository) and explicitly reconcile the166 current status, rather than reopening the finding from scratch.167- If a feature finding effectively coincides with a risk already tracked in168 `docs/bugs/security_audit/` that was deliberately accepted (a low replica169 count for HA, a disabled networkPolicy, etc.), reference the existing170 finding file instead of raising a duplicate as a "new feature finding";171 note it only if the feature makes the risk worse than it was recorded.172173## CATEGORY CHECKLIST (apply the ones relevant to the feature)174175Before the review, quickly classify the feature: which of the blocks below176apply (a new API endpoint → blocks 1,2,5,6,10; a new UI screen → blocks 1,7;177file upload → block 9; integration/webhook → blocks 4,6,8; infrastructure178change → blocks 11,12). Do not skip a block just because "the feature is179small" — small features are typically exactly the source of pinpoint holes180(see "Edge cases" below).1811821. **Authentication and authorization**183 - Does the new/changed endpoint require authentication the same way as184 the other endpoints of the same service (is there a "forgotten" open185 route)?186 - RBAC branches: what happens for a role that falls into no explicit187 branch (default/else)? Does this lead to a leak (no filter by188 assigned_user_id/owner_id)?189 - IDOR/BOLA: can you access someone else's object that the feature190 operates on by changing an ID in the URL/body?191 - Broken function level authorization: is the new administrative/bulk192 operation accessible without a role check?193 - Mass assignment/over-posting: does the new/changed API accept arbitrary194 request-body fields (role, is_admin, company_id, balance, etc.), or is195 the list of allowed fields an explicit whitelist?196 - Session/token: if the feature touches sessions/tokens — where is the197 storage, is there invalidation, is there a lifetime limit?198 - Rate limiting: if the feature adds a login/password reset/OTP-like flow199 — is there a limit on attempts?2002012. **Multi-tenancy (isolation between customer companies)** — review this202 separately from generic IDOR; a cross-tenant leak is heavier in203 consequences.204 - Every new read/write point (REST handler, WS subscription, cache key,205 search index, queue, export) — is it filtered by company_id/tenant_id206 at the DB-query level, not just at the UI/router level?207 - Is the company_id match checked by an explicit comparison of the value208 from the token/context against the record's company_id, rather than209 assumed?210 - Shared resources (Redis keys, RabbitMQ queues, file storage) — can a211 key/name collide between companies given identical internal IDs?212 - A new Alembic migration/DDL: does a new table/column that stores a213 specific company's data have `company_id`/`tenant_id` and an index on214 it — a structural gap at the schema level cannot be caught by a215 line-by-line query review if the column itself is missing.2162173. **WebSocket / realtime** (if the feature touches a realtime channel)218 - Is the token/role/company_id checked at connect AND separately at each219 channel/room subscription (join)?220 - Can a client subscribe to someone else's channel by supplying/guessing221 a room-id/dialog-id/user-id?222 - Is broadcast filtered by company_id/role before sending, or does the223 server rely on the client "just not being subscribed"?2242254. **Internal-API between services** (if the feature adds/changes226 `/internal/*`)227 - Does it require a shared-secret/mTLS the same way as the other228 endpoints of the same class of operation in other services? Is the229 secret actually verified (not merely declared in env)?230 - Can the new internal endpoint be called directly from outside the231 cluster?2322335. **Injections (SQL / NoSQL / Command / Template / Deserialization)**234 - Building queries by concatenation/f-string/format instead of235 parameterized queries/ORM — especially in new query parameters236 (filters, search, sorting).237 - "Manual" escaping — verify completeness (backslash, unicode, nested238 quotes).239 - Command injection: new subprocess/os.system/exec with user input.240 - Insecure deserialization of new data from a queue/webhook/inter-service241 call (pickle, yaml.load without SafeLoader, eval/exec).2422436. **SSRF** (if the feature makes an outbound HTTP request to an external244 URL)245 - Is there a domain allow-list, blocking of private/internal IP ranges246 (169.254.x.x, 10.x, 172.16-31.x, 192.168.x, 127.x, cloud metadata)?247 - Is the webhook's signature/origin verified before the system initiates248 a response request to a URL from its body?2492507. **XSS** (including client-side widgets, if the feature is a251 frontend/embeddable component)252 - innerHTML/dangerouslySetInnerHTML/document.write with untrusted data.253 - If the feature is a widget embedded on third-party sites: the254 vulnerability is visible to the end users of your platform's customers —255 qualify severity accounting for the expanded blast radius.256 - Are CSP/clickjacking headers not weakened by the new code?2572588. **Secrets and PII handling** (if the feature touches259 integrations/tokens/PII)260 - New secrets in code/configs tracked by git.261 - New integration tokens in the DB — plaintext or encrypted?262 - Secret masking in new logs — does it work for the new data types the263 feature introduced?2642659. **File upload and storage** (if the feature adds upload/download)266 - MIME-type/extension validation (do not trust the client's267 Content-Type).268 - Size limits, protection against zip bombs.269 - Path traversal when building a path from user input.270 - Public serving — does it require authentication if the files contain271 PII?27227310. **Dependencies and supply chain** (if the feature added new packages)274 - Criticality of new dependencies, whether a safer alternative exists.275 - A new internal package — installed from a private index/local path, or276 by a bare name that can be substituted from public PyPI/npm (dependency277 confusion)?27827911. **Docker / containers** (if the feature changes the Dockerfile)280 - Is USER set (non-root)? Are secrets not passed via ARG/ENV?28128212. **Kubernetes / Helm** (if the feature changes values/manifests)283 - Are networkPolicy/securityContext/resources not weakened by the new284 values file relative to the project's existing baseline?285 - Secrets via Kubernetes Secrets, not plaintext in values.yaml?28628713. **Error handling and observability**288 - A new broad except that logs and returns None/an empty result without289 re-raise — does this mask a failed authorization check as "allowed"?290 - Are new security events (failed authorizations, role changes) logged291 separately?292 - Leakage of internal information through new error messages to the293 outside.29429514. **CI/CD** (if the feature changes the pipeline)296 - CI script injection: is unvalidated external input (PR title, branch297 name) interpolated directly into a `run:` step?298 - Does the new security gate actually block the merge, or does it only299 print a warning?300301## EDGE CASES OFTEN MISSED WHEN TESTING A FEATURE302303- Functionality protected at the UI level (button hidden) but accessible304 directly through the API without a backend check.305- A race condition in "check-then-act" (the role check and the action are306 not atomic).307- Behavior for soft-deleted records — are they accessible through a new308 endpoint that does not account for the deletion flag?309- The bulk variant of the new feature (bulk endpoint) — often added "quick310 and dirty" with weaker-verified authorization than its single-item311 counterpart.312- The webhook the feature adds — is the signature/origin verified?313- The feature's feature flag, turned off "temporarily for debugging" and314 left off by default in the config.315- dev/staging/prod differences — a fix applied in one helm-values316 configuration may be absent in another.317- Data export, if the feature adds it — is authorization on the exported318 volume as strict as on ordinary reads?319- An old/duplicate path left behind after the feature's refactoring (e.g.320 the old endpoint was not removed, it just stopped being called from the321 frontend — it is still reachable and not updated to the new authorization322 logic).323324## SEVERITY SCALE (shared with the full repository audit)325326A shared scale is needed so findings are comparable across individual327feature checks and full audits (see `security-audit-full`).328329- **Critical**: an unauthenticated external attacker achieves full compromise330 through this feature (RCE, access to all data of all customer companies,331 full authentication bypass).332- **High**: an authenticated user (including one with a minimal role) gains333 access to someone else's data/privileges through this feature — including334 cross-tenant access — or an unauthenticated attacker gains access to the335 data of one company/one user.336- **Medium**: requires specific conditions (a race, a particular role, MITM,337 social engineering) or is limited to metadata leakage/DoS without data338 loss.339- **Low**: a best-practice violation with no direct exploitation scenario at340 the time of the check.341342For each finding, state who can exploit it (anonymous / authenticated user /343internal network only) and what is lost (read / write / full compromise).344345## REPORT FORMAT3463471. Executive summary (no technical jargon): is the feature secure to348 release, what is critical, what is a business/regulatory risk, what to do349 first.3502. SCOPE — the final list of reviewed files/directories/services (see the351 "Input" section above) and an explicit note on what was left OUTSIDE the352 SCOPE and why (e.g. "shared library X was not re-reviewed since it did353 not change in this feature").3543. Feature verdict: "ready to release" / "ready with caveats (see355 low/medium)" / "not ready — there are critical/high findings" — in one356 phrase at the top of the report.3574. Full list of findings: file:line, category (may reference OWASP Top 10 /358 OWASP API Security Top 10 / CWE), a concrete exploitation scenario,359 severity with justification, status, remediation recommendation.3605. A "what was done well" section — strong patterns in the feature's361 implementation worth replicating.3626. Action plan: what blocks the release now (critical/high), what can be363 fixed after release with a ticket (medium/low).3647. A "what was not checked" section — coverage limitations (no access to the365 prod environment, no ability to run a scanner, etc.), so the absence of366 findings does not read as "everything there is clean".367368## FINDING FORMATTING RULES369370Before starting, check whether a report for this same feature already exists371in `docs/bugs/security_audit/` (e.g. by its feature-slug or ISSUE-ID from a372previous run of this same skill). If it does, do not start numbering from373zero: continue the existing ID sequence and update the status of already374known findings ("not fixed" → "fixed", etc.), rather than re-raising them as375new.376377For each finding, the following are mandatory:378379- A stable finding ID (e.g. `SEC-<ISSUE-ID or feature-slug>-001`), unique380 within the reports for this feature (see above on re-runs).381- The file path and line number (or range).382- The vulnerability name and category (OWASP Top 10 / OWASP API Security Top383 10 / CWE).384- A concrete exploitation scenario: "if you make request X with parameter Y,385 the system will return/do Z" — not abstract wording like "there may be a386 vulnerability".387- Severity with justification (who can use it, what is lost).388- A remediation recommendation — concrete ("add an else branch with an389 explicit denial", "enable flag X by default", "replace the f-string with a390 parameterized query").391392## RUNNING THE CHECK (practical instructions)3933941. First, YOURSELF (in the main thread), do the "Input" section — determine395 the input type (directory/branch/diff, document, YouTrack issue) and build396 the SCOPE. Do not delegate this step: a subagent starts without the397 conversation context and does not know what was meant by "the feature".398 Record the SCOPE explicitly before moving to the review.3992. Classify the feature by change type (new API, new UI, integration/webhook,400 file upload, infrastructure, etc.) and select the applicable checklist401 blocks.4023. Check whether a report for this feature already exists in403 `docs/bugs/security_audit/` (see "Finding formatting rules") — this is a404 cheap check that saves rework and preserves the continuity of finding405 numbering.4064. Run the focused automated checks of PASS 1 on the files/dependencies in407 SCOPE (semgrep/bandit focused, SCA on the changed lock files, gitleaks on408 the feature's diff).4095. Perform the manual line-by-line review of PASS 2. If the SCOPE spans410 several services/directories and the Agent tool is available, split it411 into independent zones and launch a separate subagent per zone (in412 foreground, if the result is needed for a further decision in this same413 dialogue) so as not to cut corners across the whole volume at once. Give414 each subagent the concrete paths and the applicable sections of this skill415 (checklist, severity scale, finding format) — a subagent does not see this416 file itself. Record confirmed findings in an intermediate file as you417 review each zone, rather than keeping them only in context until the final418 report.4196. Perform PASS 3 — the feature's points of contact with the platform's420 existing security invariants (authentication, multi-tenancy, internal-API,421 shared libraries).4227. Consolidate all three passes into a single report per the format above,423 remove duplicates, but do not merge findings of different natures (a424 scanner found a pattern ≠ manual review confirmed exploitability — record425 both facts if both exist). Save the final report as a file at426 `docs/bugs/security_audit/<feature-slug>-security-review.md` (slug — by427 ISSUE-ID or by feature/directory name) — this is the same place where the428 registry of past audit findings lives, and the next run of this skill on429 the same feature should find and update it, rather than recreating it from430 scratch.4318. Explicitly state which checks were NOT performed (no access to prod432 secrets, no access to runtime logs, no ability to run a scanner, etc.) —433 this is part of an honest report, not its weakness.4349. If the project has a `security-review` skill/agent configured (a quick435 review of pending changes on the current branch), you can use it as a436 starting point for PASS 2 on the changed files, but do not limit yourself437 to the diff: the feature may rely on existing code that did not change in438 the current branch but participates in its security model (see PASS 3).439440This is testing, not implementation: the developer makes the changes based on441the report, not you within this skill.442