@@ -506,6 +506,136 @@ Example:
506506 git node security --remove-report=12345
507507```
508508
509+ ### ` git node security --validate-reports `
510+
511+ This command retrieves all triaged HackerOne reports for the Node.js program and
512+ produces a local validation report for each one. It is intended to help the
513+ security team review whether a report still looks valid under the Node.js threat
514+ model and whether the current HackerOne severity/CVSS is consistent with the
515+ available evidence.
516+
517+ The command uses the existing HackerOne credentials configured in ` .ncurc ` . It
518+ does not modify HackerOne reports, labels, comments, or severity. The output is
519+ only a local triage aid and still requires human review.
520+
521+ ``` sh
522+ git node security --validate-reports
523+ git node security --validate-reports --validate-reports-format=json
524+ git node security --validate-reports --validate-reports-output=reports.md
525+ git node security --validate-reports --llm=codex --node-repo=/path/to/node
526+ git node security --validate-reports --llm=codex --llm-model=gpt-5.5
527+ git node security --validate-reports --llm=codex --no-validate-reports-confirm
528+ git node security --validate-reports --llm=codex --no-validate-reports-cache
529+ git node security --validate-reports --llm=claude --node-repo=/path/to/node
530+ git node security --validate-reports --llm=copilot --node-repo=/path/to/node
531+ git node security --validate-reports --llm=copilot --llm-command=" copilot -p"
532+ ```
533+
534+ By default, the command runs a heuristic pass only. The heuristic checks the
535+ report title, vulnerability information, impact, description, comments, current
536+ severity, CVSS vector, and weakness metadata for common Node.js security topics.
537+ It can identify obvious mismatches, such as a CVSS vector whose calculated
538+ rating does not match the HackerOne rating. Keyword matches are treated only as
539+ topic hints, not as proof that a report is valid or invalid. This is deliberate:
540+ HackerOne report text is reporter-controlled, so words like ` request smuggling `
541+ or ` permission model ` are not enough to make a threat-model decision. The
542+ heuristic output is deliberately conservative and always leaves threat-model
543+ validity as ` needs-manual-review ` .
544+
545+ Use ` --llm=<provider> ` to ask an LLM CLI to produce a structured assessment for
546+ each report. Supported providers are ` codex ` , ` claude ` , and ` copilot ` .
547+
548+ When LLM mode is enabled, the command asks before assessing each report and shows
549+ the report title, current severity, CVSS vector, and weakness. After each LLM
550+ assessment, it prints a readable summary with:
551+
552+ - the report URL and title
553+ - the provider and model/cache identity
554+ - validity under the Node.js threat model
555+ - whether the current severity is correct
556+ - current severity/CVSS and suggested severity/CVSS
557+ - a colored CVSS metric diff when the suggested vector differs
558+ - CWE
559+ - confidence from 0 to 100
560+ - threat model/documentation references used by the model
561+ - reasoning
562+
563+ Use ` --no-validate-reports-confirm ` for batch mode without the per-report
564+ prompts. Use ` --validate-reports-limit=<n> ` to test the flow against a smaller
565+ number of reports.
566+
567+ #### LLM prompt and reasoning
568+
569+ The LLM prompt is designed to keep the model anchored to the Node.js threat
570+ model and local documentation instead of only reasoning from the report text.
571+ For each report, the prompt instructs the model to:
572+
573+ - read ` SECURITY.md ` from the Node.js checkout supplied through ` --node-repo `
574+ - inspect relevant files under ` doc/ ` for the affected API or subsystem
575+ - apply the documented Node.js threat model, including treatment of application
576+ code, caller-supplied API inputs, third-party modules, unsupported platforms,
577+ and inspector/debugger access
578+ - decide whether the report is valid under that threat model
579+ - decide whether the current HackerOne severity/CVSS is correct
580+ - use reports with the same CWE/weakness as precedent context when available
581+ - avoid copying precedent blindly when ` SECURITY.md ` or ` doc/ ` point to a
582+ different result
583+ - return only JSON matching the schema expected by the command
584+
585+ The report payload sent to the model contains the HackerOne report id, title,
586+ URL, state, current severity, current CVSS vector, weakness metadata, reporter,
587+ report body fields, comments, heuristic findings, and comparable reports with
588+ the same weakness. Comparable reports include their title, URL, current
589+ severity/CVSS, state, and any team summary available through HackerOne. This
590+ helps the model account for previous team decisions while still checking the
591+ current report against the threat model.
592+
593+ The model must return these fields:
594+
595+ - ` validity ` : ` valid ` , ` invalid ` , or ` needs-more-info `
596+ - ` severity_correct ` : boolean
597+ - ` suggested_severity ` : ` none ` , ` low ` , ` medium ` , ` high ` , ` critical ` , or
598+ ` informational `
599+ - ` suggested_cvss ` : a CVSS vector or ` N/A `
600+ - ` cwe ` : the best matching CWE
601+ - ` confidence ` : a number from 0 to 100
602+ - ` reasoning ` : a concise explanation
603+ - ` threat_model_references ` : references to ` SECURITY.md ` and relevant ` doc/ `
604+ material used for the decision
605+
606+ #### LLM commands and cache
607+
608+ The ` --llm-command ` option can override the default provider command. The prompt
609+ is sent on stdin and the command must print a JSON object matching the expected
610+ schema.
611+
612+ The model label is inferred from the local LLM CLI configuration when possible.
613+ For example, Codex reads ` ~/.codex/config.toml ` and includes
614+ ` model_reasoning_effort ` in the cache label. Use ` --llm-model ` to override the
615+ provider command model and the cache identity. If the model cannot be inferred,
616+ the cache entry includes a comment explaining that ` default ` was used.
617+
618+ Successful LLM assessments are cached locally in
619+ ` .ncu-cache/security-report-validation ` using the report, provider, model, and
620+ prompt as the cache key. Use ` --no-validate-reports-cache ` to force a fresh LLM
621+ assessment.
622+
623+ #### Options
624+
625+ | Option | Description |
626+ | --- | --- |
627+ | ` --validate-reports-format=markdown\|json ` | Select the final output format. Defaults to ` markdown ` . |
628+ | ` --validate-reports-output=<file> ` | Write the final output to a file instead of stdout. |
629+ | ` --validate-reports-limit=<n> ` | Validate at most ` n ` triaged reports. Useful for testing the flow. |
630+ | ` --validate-reports-confirm ` | Ask before each LLM assessment and before continuing to the next report. Enabled by default. |
631+ | ` --no-validate-reports-confirm ` | Disable interactive prompts for batch runs. |
632+ | ` --validate-reports-cache ` | Reuse cached successful LLM assessments. Enabled by default. |
633+ | ` --no-validate-reports-cache ` | Ignore existing LLM cache entries and do not reuse them. |
634+ | ` --llm=codex\|claude\|copilot ` | Ask an LLM CLI to assess each report. |
635+ | ` --llm-model=<model> ` | Override the provider model and cache identity. |
636+ | ` --llm-command=<command> ` | Override the command used for LLM assessment. The prompt is sent on stdin. |
637+ | ` --node-repo=<path> ` | Path to a Node.js checkout containing ` SECURITY.md ` and ` doc/ ` . Defaults to the current directory. |
638+
509639## ` git node status `
510640
511641Return status and information about the current git-node land session. Shows the following information:
0 commit comments