A PSIRT is the team that receives, triages, fixes and discloses vulnerabilities in the products a company ships; a CSIRT handles incidents in the company's own infrastructure. Build it on the six service areas of the FIRST PSIRT Services Framework, starting with a staffed intake, a written triage process, response targets per severity, and a way to publish advisories and CVE records. Choose a distributed, centralized or hybrid model to fit your product portfolio, become a CVE Numbering Authority once you ship enough products to need one, and track every case in a record with timestamps so you can show what happened and when.
- Do publish one intake route (VDP and
security.txt) and staff it; an unread mailbox is the most common PSIRT failure. - Do triage with a written qualification step, reproduction and a CVSS 4.0 vector, then prioritize with the decision table in /frameworks/vulnerability-prioritization/.
- Do set response targets per severity, with a much shorter path when exploitation is reported, and measure every case against them.
- Do become a CNA when you ship products regularly, and publish CVE records within the CNA rules' 72-hour limit after disclosure.
- Don't run PSIRT and incident response as strangers: an exploited product vulnerability is both a PSIRT case and an incident.
| Setting | Value | Note | Source |
|---|---|---|---|
| Service framework | FIRST PSIRT Services Framework 1.1 | Six service areas: stakeholder ecosystem management, vulnerability discovery, triage and analysis, remediation, disclosure, training and education. | FIRST |
| CNA rules | CNA Operational Rules 4.2.0, effective 25 August 2026 | Replaced 4.1.0 (effective 14 May 2025). | CVE Program |
| Publish a CVE record after disclosing its ID | Should within 24 hours; must within 72 hours | — | CNA rules 4.2.0, 4.5.1.3 and 4.5.1.4 |
| Acknowledge a report | 2 calendar days (example) | Local target; publish it in the VDP. | — |
| Fix target by severity | Critical 30, high 60, medium 90, low 180 days; exploited 7 days (example) | Local targets. Google Project Zero gives vendors 90 days, and 7 days for bugs exploited in the wild. | — |
| EU CRA reporting | Early warning within 24 hours of becoming aware of an actively exploited vulnerability | Applies from 11 September 2026 to products in scope; see /frameworks/cra-reporting-runbook/. | Regulation (EU) 2024/2847, Article 14 |
- Send a test report through every published channel (
security.txtcontact, web form, support) and time the acknowledgement. - Run the SLA script over all open cases each week and review every overdue stage with its owner.
- Pick the last three disclosed vulnerabilities and check that each has a CVE record with CWE, affected and fixed versions, published within 72 hours of the advisory.
- Check that an exploited-vulnerability case opens an incident and starts the CRA clock check automatically.
- Review the FIRST service areas once a year and record which services you provide and which you deliberately do not.
- Applies to
- FIRST PSIRT Services Framework 1.1
- CVE CNA Operational Rules 4.2.0 (effective 25 August 2026)
- ISO/IEC 29147:2018 (disclosure) and 30111:2019 (handling)
- Artifacts JSON Schema draft 2020-12 (validated with Ajv); Python 3.14 (tested)
Organizations that ship software or devices to customers, including SaaS providers, that need a repeatable way to handle vulnerability reports and publish fixes and advisories.
- Part of
- Workflow: Respond to a vulnerability
Learning goals and prerequisites
What you will learn
- Explain what a PSIRT does and choose a distributed, centralized or hybrid model.
- Design intake, triage and response targets, and track them per case.
- Decide when to become a CNA and what the CNA rules 4.2.0 require.
- Coordinate multi-vendor vulnerabilities with embargoes and a lead coordinator.
Before you start
Product security leads, AppSec engineers and engineering managers who set up or run vulnerability handling for shipped products
- Know which products and versions your company supports.
- Read the coordinated disclosure guide first.
- For the artifacts: Python 3.11 or later; Node.js with Ajv to validate the schema.
Refresh first: Run coordinated vulnerability disclosure from report to advisory
Go to the guided practiceOne vulnerability report through the PSIRT
- ReportA finder reports through the VDP form or the
security.txtcontact. The report is untrusted until it is qualified and reproduced. - Acknowledge and triageThe PSIRT acknowledges with a case ID and the next update date, qualifies the report and has the product team reproduce it and score a CVSS 4.0 vector.
- Reserve a CVE IDOnce there is reasonable evidence of a vulnerability that will be disclosed, the PSIRT, as a CNA or through one, reserves a CVE ID.
- Fix and agree the dateThe product team fixes every supported version; the PSIRT agrees the disclosure date with the finder.
- DiscloseThe PSIRT publishes the advisory and CSAF document, notifies customers and publishes the CVE record: the CNA rules say within 24 hours of disclosing the ID, and require it within 72.
A product security incident response team handles vulnerabilities in the products and services a company ships: it receives reports, gets them triaged and fixed, and tells customers what to do. The FIRST PSIRT Services Framework puts the difference simply: an enterprise CSIRT focuses on the security of the organization's own systems and networks, while the PSIRT focuses on products. The two must work together, because an exploited product vulnerability is both a PSIRT case and, for a SaaS provider or its customers, an incident.
NIST SSDF task RV.1.3 asks for a policy on vulnerability disclosure and remediation and gives "have a PSIRT and processes in place" as an example. Small companies can run the PSIRT function with a part-time lead and an on-call rotation; what matters is that every report has an owner and a clock from the moment it arrives.
The framework groups PSIRT work into six service areas, each with numbered services. Nobody provides all of them on day one. Use the list to decide what you provide now, what later, and what you leave to others, and write that down in the PSIRT charter.
| Service area | Services in the framework | Build first |
|---|---|---|
| 1 Stakeholder ecosystem management | 1.1 internal stakeholders, 1.2 finder community engagement, 1.3 community and organizational engagement, 1.4 downstream stakeholders, 1.5 incident communications within the organization, 1.6 recognition for finders, 1.7 stakeholder metrics | Named contacts in engineering, legal, support and communications; a thank-you or hall-of-fame practice |
| 2 Vulnerability discovery | 2.1 intake of vulnerability reporting, 2.2 identifying unreported vulnerabilities, 2.3 monitoring product component vulnerabilities, 2.4 identifying new vulnerabilities, 2.5 discovery metrics | One intake route and monitoring of third-party components in your SBOMs |
| 3 Vulnerability triage and analysis | 3.1 qualification, 3.2 established finders, 3.3 reproduction | A written qualification checklist and a reproduction environment |
| 4 Remediation | 4.1 remedy release management plan, 4.2 remediation, 4.3 incident handling, 4.4 release metrics | Fix targets per severity and a list of supported versions |
| 5 Vulnerability disclosure | 5.1 notification, 5.2 coordination, 5.3 disclosure, 5.4 vulnerability metrics | An advisory template and a CVE route |
| 6 Training and education | 6.1 training the PSIRT, 6.2 training development teams, 6.3 training validation teams, 6.4 continuing education, 6.5 feedback mechanisms | Feed root causes into developer training; see /frameworks/developer-security-training/ |
The framework describes three models. Pick by portfolio and size, then document reporting lines and authority in the charter, because a PSIRT that cannot make product teams act will miss its targets.
| Model | How it works | Fits when |
|---|---|---|
| Distributed | A small core PSIRT works with representatives in each product team, who do most triage and remediation | A large, diverse portfolio; the cost spreads across product teams and scales with them |
| Centralized | A larger PSIRT staff, drawn from several departments, reports to executives responsible for product security | Few products, high regulatory or customer pressure, or teams without security depth |
| Hybrid | Central intake, coordination and disclosure; product teams own triage depth and fixes | Most mid-size companies; often the result of growing out of a distributed model |
Write the roles down before the first case. The RACI below is a starting point; R does the work, A is accountable, C is consulted, I is informed. Security champions, described in /frameworks/security-champions-program/, are natural product-team contacts.
| Activity | PSIRT lead | Product team | Legal and communications | Support | Executive sponsor |
|---|---|---|---|---|---|
| Acknowledge and qualify the report | A/R | C | I | I | - |
| Reproduce and score | A | R | - | - | - |
| Fix all supported versions | C | A/R | - | I | - |
| Agree the disclosure date with the finder | A/R | C | C | - | I |
| CVE record and advisory | A/R | C | C | I | - |
| Customer notification | A | C | R | R | I |
| Regulatory reporting (for example CRA) | R | C | A | - | I |
Publish one documented route and accept reports wherever they land. The VDP and security.txt are the front door; see /domains/appsec/vulnerability-response/vdp-bug-bounty-pentest/ for both. Support staff need a rule to forward anything that looks like a vulnerability report to the PSIRT queue the same day, and the PSIRT needs to watch upstream advisories for the components in its SBOMs, which the framework calls monitoring product component vulnerabilities.
Acknowledge every report with a case ID and the next update date, even before triage. The ticket should record the source, because the framework treats finders who report often (established finders) differently in qualification: their reports usually need less proof before reproduction starts.
- External finders: VDP form or the
security.txtcontact; bug bounty platform if you run one. - Customers: through support, with a forwarding rule and a template that asks for version and impact.
- Upstream suppliers and open-source projects: advisories for components in your SBOMs; see /domains/appsec/vulnerability-response/dependency-vulnerability-response/.
- Coordinators such as CERT/CC, which runs the VINCE platform for multi-party cases, and national CSIRTs.
- Internal sources: penetration tests, code review, scanners and incident investigations.
Qualification decides whether the report is in scope, whether it describes a vulnerability in a supported product version, and whether it duplicates a known case. Reproduction confirms the behavior on a supported version with synthetic data, without widening exposure. Score a CVSS 4.0 vector for the advisory and the CVE record, and decide priority with exploitation, exposure and reachability as in /frameworks/vulnerability-prioritization/; a KEV listing or a report of exploitation in the wild moves the case to the exploited track at once.
Record a decision for every report, including "not a vulnerability" with the reason and "not affected" with evidence, which may become a VEX statement for customers. If the finder disagrees, follow the evidence-boundary approach in /domains/appsec/vulnerability-response/coordinated-disclosure/.
ISO/IEC 29147:2018 and 30111:2019 describe the disclosure and handling processes but leave the timings to you, so set targets, publish the ones that finders care about and measure every case. Outside expectations shape them: Google Project Zero gives vendors 90 days to make a fix available and 7 days for bugs exploited in the wild, and many researchers follow similar deadlines. The EU Cyber Resilience Act adds a 24-hour early warning for actively exploited vulnerabilities in products in scope, from 11 September 2026.
| Stage | Example target (calendar days from receipt) | Notes |
|---|---|---|
| Acknowledge | 2 | Automatic receipt is not acknowledgement; a person confirms the case and the next update date |
| Triage decision | 7 | Qualified, reproduced, scored, owner assigned |
| Fix released, critical | 30 | For all supported versions, or a documented mitigation |
| Fix released, high / medium / low | 60 / 90 / 180 | Low may ship in the next scheduled release if earlier |
| Exploited in the wild | 7 for the fix or mitigation | Also opens an incident; check CRA reporting the same day |
| CVE record after the advisory | Within 24 hours (rule: must within 72) | CNA rules 4.2.0, 4.5.1.3 and 4.5.1.4 |
Keep each case as structured data, whatever tracker you use, so you can report on it and so the same fields feed the advisory, the CVE record and the CSAF document. The schema below names the source, products with VEX-style statuses, the state, severity and vector, CWE, exploitation, the CVE, any embargo date and timestamps for each stage. It validates with Ajv 8 against JSON Schema draft 2020-12.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://psirt.example/schemas/psirt-case.json",
"title": "PSIRT case",
"type": "object",
"required": ["id", "source", "products", "state", "severity", "received", "owner"],
"properties": {
"id": {"type": "string", "pattern": "^PSIRT-[0-9]{4}-[0-9]{4}$"},
"source": {"enum": ["vdp", "bug-bounty", "customer", "internal", "upstream", "coordinator", "researcher-public"]},
"products": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["name", "versions", "status"],
"properties": {
"name": {"type": "string"},
"versions": {"type": "string"},
"status": {"enum": ["under_investigation", "known_affected", "known_not_affected", "fixed"]}
}
}
},
"state": {"enum": ["received", "acknowledged", "triaged", "fixing", "fix-released", "disclosed", "closed", "rejected"]},
"severity": {"enum": ["critical", "high", "medium", "low", "none", "unknown"]},
"cvss_vector": {"type": "string", "pattern": "^CVSS:(3\\.1|4\\.0)/"},
"cwe": {"type": "array", "items": {"type": "string", "pattern": "^CWE-[0-9]+$"}},
"exploited": {"type": "boolean", "description": "Reliable evidence of exploitation; starts CRA Article 14 clocks for in-scope products"},
"cve": {"type": "string", "pattern": "^CVE-[0-9]{4}-[0-9]{4,}$"},
"embargo_until": {"type": "string", "format": "date"},
"owner": {"type": "string"},
"received": {"type": "string", "format": "date-time"},
"acknowledged": {"type": "string", "format": "date-time"},
"triaged": {"type": "string", "format": "date-time"},
"fix_released": {"type": "string", "format": "date-time"},
"disclosed": {"type": "string", "format": "date-time"},
"advisory": {"type": "string", "format": "uri"}
},
"additionalProperties": false
}Run a small report every day or week over the case records. The script applies the example targets and marks each stage as met, missed, open with its due date, or overdue. On 10 October 2026, with three sample cases, it reported a critical case received on 1 September whose fix was overdue, a customer report received on 6 October whose acknowledgement was overdue, and an exploited high-severity case whose 7-day fix target had passed, with a reminder to check CRA reporting.
"""Report each PSIRT case against an example SLA policy (calendar days, local choices).
Usage: python sla_status.py cases.json 2026-10-10T12:00:00Z
"""
import json
import sys
from datetime import datetime, timedelta
POLICY = { # target days from "received"; exploited cases use the "exploited" fix target
"acknowledge": 2,
"triage": 7,
"fix": {"critical": 30, "high": 60, "medium": 90, "low": 180, "exploited": 7},
}
def ts(value):
return datetime.fromisoformat(value.replace("Z", "+00:00"))
def status(case, now):
received = ts(case["received"])
checks = [("acknowledge", "acknowledged", POLICY["acknowledge"]), ("triage", "triaged", POLICY["triage"])]
if case["severity"] in POLICY["fix"]:
days = POLICY["fix"]["exploited"] if case.get("exploited") else POLICY["fix"][case["severity"]]
checks.append(("fix", "fix_released", days))
for stage, field, days in checks:
due = received + timedelta(days=days)
done = case.get(field)
if done:
state = "met" if ts(done) <= due else "missed"
else:
state = "OVERDUE" if now > due else f"open, due {due:%Y-%m-%d}"
yield stage, state
if __name__ == "__main__":
cases = json.load(open(sys.argv[1], encoding="utf-8"))
now = ts(sys.argv[2])
for case in cases:
line = "; ".join(f"{stage} {state}" for stage, state in status(case, now))
flag = " [exploited: check CRA Article 14 reporting]" if case.get("exploited") else ""
print(f"{case['id']} {case['severity']:8} {line}{flag}")A CNA assigns CVE IDs and publishes CVE records for vulnerabilities within an agreed scope, usually its own products. Becoming one lets you publish authoritative records on your own schedule, with your own CWE, CVSS and version data, instead of waiting for another CNA. Under the CNA Operational Rules 4.2.0, effective 25 August 2026, a CNA should assign an ID when it has reasonable evidence of a vulnerability that is or will be publicly disclosed and is in its scope; must publish the record within 72 hours of disclosing the ID; and every record must name at least one affected product, a problem type (preferably a CWE), a description and a public reference. The rules also say a CNA must not use the type of technology, such as cloud or AI, as the only reason to decide whether to assign, and provide an exclusively-hosted-service tag for vulnerabilities that exist only in a hosted service.
To join, a CNA needs a scope definition, a public vulnerability disclosure policy and a public place where it publishes advisories, and it onboards through a Root. Organizations in Europe can now join under the ENISA Root. If you are not a CNA, ask the CNA whose scope covers your product: a vendor CNA, GitHub for open-source projects hosted there (GitHub is a CNA and assigns IDs for repository security advisories), or a CNA of last resort. See /domains/appsec/vulnerability-response/security-advisories-csaf-vex/ for publishing the record and the advisory.
Many vulnerabilities affect more than one vendor: a shared library, a protocol, or your component inside someone else's product. FIRST's "Guidelines and Practices for Multi-Party Vulnerability Coordination and Disclosure" (version 1.1, 2020) covers the common cases, from a vulnerability with no affected users to public disclosure or exploitation before the vendor knew. Its practical advice: give vendors a reasonable embargo to investigate and fix, agree timelines before disclosure and tell downstream vendors clearly, pick a single lead coordinator when several are involved, and set up upstream and downstream channels before you need them.
The PSIRT framework adds the intermediate-vendor case: if you supply components to other vendors, notify their PSIRTs of vulnerabilities in what you supply, and put timely notification into your contracts. For your own suppliers, ask for the same.
- Time to acknowledge, triage and fix by severity, as medians and as the share of cases within target.
- Cases overdue at each stage today, with owners.
- Share of vulnerabilities fixed before public disclosure, and cases disclosed by others first.
- Advisory quality: revisions caused by wrong version ranges or missing products.
- Root causes by CWE, fed to developer training and to the vulnerability classes the company wants to eliminate.
- Finder experience: repeat reporters and complaints about silence, from the case history.
Guided practice
Kestrel, a fictional company with a SaaS console, an on-premises agent sold in the EU and an open-source SDK on GitHub, wants to formalize its PSIRT. Use the cases and facts below to make three decisions and fix the backlog.
Supplied scenario material
Kestrel (fictional): 18 product teams, 1 security engineer, champions in 6 teams.
Current intake: security@kestrel.example, read by the security engineer "when possible"; no security.txt.
Open cases on 2026-10-10:
K-1 reported 2026-08-20 by a researcher: auth bypass in agent 5.x (critical); acknowledged 2026-08-29; fix in progress
K-2 reported 2026-10-07 via support: SSRF in console import (high); no acknowledgement yet
K-3 reported 2026-10-08 by CERT/CC: a vulnerability in a compression library used by agent and SDK; three other vendors affected; embargo proposed until 2026-11-04
K-4 reported 2026-10-09: customer says K-1 is being exploited against their agent
CVEs so far: requested from MITRE as CNA of last resort; two took more than a month.1. Pick the model and fix intake
Choose an organizational model and the first two intake changes.
Expected result and reasoning
Hybrid: central intake and disclosure with one security engineer as PSIRT lead, product-team champions as triage contacts. Publish
security.txtand a VDP pointing to a monitored queue with an on-call rotation, and add a support forwarding rule.2. Apply the targets
Using the example targets, state the status of K-1 and K-2.
Expected result and reasoning
K-1: acknowledgement took 9 days (target 2, missed); the 30-day critical fix target fell on 2026-09-19, so the fix is overdue. K-2: received 2026-10-07, acknowledgement due 2026-10-09, overdue; triage due 2026-10-14.
3. Handle the exploitation report
What changes for K-1 after K-4?
Expected result and reasoning
K-1 moves to the exploited track: open an incident, ship a fix or mitigation within days, notify customers, and because the agent is sold in the EU, check CRA Article 14 reporting with a 24-hour early warning from becoming aware of exploitation.
4. Coordinate K-3
How should Kestrel handle the multi-vendor case?
Expected result and reasoning
Accept CERT/CC as lead coordinator, keep the embargo unless exploitation appears, fix both agent and SDK, prepare advisories for 2026-11-04, and notify downstream customers that embed the SDK according to the agreed timeline.
5. Decide on the CNA question
Should Kestrel become a CNA?
Expected result and reasoning
Yes, with scope covering its products, since delays through the CNA of last resort are slowing advisories; it needs a public VDP and advisory location first. Meanwhile, the SDK can get CVE IDs through GitHub repository security advisories, because GitHub is the CNA for projects it hosts unless another CNA covers them.
Kestrel and its cases are fictional; the targets are examples, not values from FIRST, ISO or the CVE Program. Confirm CRA scope and reporting details for real products with the runbook and legal counsel.
Save a draft on this device to resume later. Automatic saving begins after you choose Save. Drafts are never sent by this application; use synthetic data.
No draft saved on this device yet.
Sources & further reading
The standards, specifications and documentation behind the guidance above. Each is the evidence for a claim on this page; consult it for detail beyond the defaults and versions listed here.
- FIRST: PSIRT Services Framework 1.1
- FIRST: Guidelines and Practices for Multi-Party Vulnerability Coordination and Disclosure. Version 1.1 (Spring 2020).
- CVE Program: CNA Operational Rules 4.2.0. Effective 25 August 2026.
- CVE Program: CVE Numbering Authorities
- ENISA: Join the global CVE Program under the ENISA Root
- GitHub Docs: repository security advisories (GitHub as a CNA)
- CERT/CC: VINCE coordination platform
- CERT/CC Guide to Coordinated Vulnerability Disclosure
- Google Project Zero: vulnerability disclosure policy
- NIST SP 800-218: SSDF 1.1 (RV.1.3). Version 1.1 (February 2022).
Reference information
- SDLC phase
- Maintenance