Guide for leads, security and engineering
Security and development, one team
Safe code and safe pipelines are not delivered by a security team reviewing a finished product, or by developers left alone with a scanner. They come from two groups with different expertise agreeing on goals, splitting the work clearly, and building the safe way into the tools everyone already uses.
Shared goals and metrics
If security is measured on findings opened and development on features shipped, the two teams are set up to fight. Pick a small set of numbers both sides own, review them together monthly, and put them next to delivery metrics such as the DORA four, so nobody "wins" security by stopping delivery.
| Metric | Why it matters | Good direction |
|---|---|---|
| Time to remediate, by severity | How long real risk stays open. Median and 90th percentile, not average. | Down, and inside the SLA |
| Found before merge vs after release | The share caught in the editor or pull request, where fixing is cheapest. | More before merge |
| Coverage of paved road controls | Repositories with SAST and secret scanning on pull requests, pipelines installing through the registry firewall from a lockfile. | Up, toward all |
| False positive rate per rule | Noise costs trust. Rules developers mark as wrong most of the time get fixed or retired. | Down |
| Open exceptions and their age | Accepted risk that is supposed to be temporary. | Few, none expired |
| Time developers lose to security tooling | Blocked merges, slow pipeline stages, waiting on approvals. The cost side, measured honestly. | Down |
| Time to answer "are we affected?" | From a new advisory to a list of affected applications and owners. | Minutes, not days |
Avoid "number of findings" as a goal on either side. It rewards noisy scanners and discourages people from reporting problems.
Security champions
A champion is a developer on a product team with an interest in security and a bit of protected time for it. They are the team's first stop for security questions and the security team's way into the team's context. They are not a substitute for a security team, and not the person who fixes everything.
- Volunteers, one per team, with time agreed with their manager, for example a few hours a week.
- A regular forum with the security team: new threats, tool changes, patterns seen in findings.
- They lead threat modeling for their team, help triage findings, and review security sensitive pull requests.
- Recognition that counts: in performance reviews, in promotion cases, in visible thanks.
- Training and early access: they try new tooling and rules before everyone else.
See the OWASP Security Champions Guidebook.
Paved roads and secure defaults
A paved road is the supported, secure by default way to do a common job. If it is also the easiest way, most teams take it without being told, and security reviews shrink to the places that leave the road.
- Service templates with authentication, logging, headers and health checks already wired.
- Shared CI workflows with pinned actions, scoped tokens, SAST, secret scanning and provenance built in.
- Base images maintained centrally, minimal, non root, rebuilt on a schedule.
- One registry for every package format, so dependency policy is applied without per project setup. ForgeRepo™ does this, with a request flow for anything blocked.
- Libraries for the risky parts: auth, crypto, file upload, outbound HTTP with SSRF protection.
Threat modeling together
Developers know how the system really works. Security knows how systems like it get attacked. Threat modeling is where those meet, and it works best as a short, regular conversation rather than a document produced for an audit.
- When: a new service, a new trust boundary (a new external API, a new tenant model), new sensitive data, or a big change to authentication.
- Who: the engineers building it, the champion, one person from security, and product if the fix could change the feature.
- How long: forty five minutes, on a whiteboard, around the data flow diagram. The four questions and STRIDE are in the secure coding guide.
- Output: tickets in the team's backlog with acceptance criteria, and accepted risks recorded as exceptions with an expiry.
Who owns what
Most friction comes from unclear ownership: security assumes the team will fix it, the team assumes security will tell them when it matters. Write it down. A starting point, to adapt:
| Activity | Developers | Tech lead | Champion | AppSec team | Platform / DevOps | Eng manager |
|---|---|---|---|---|---|---|
| Secure coding standard | C | C | C | A/R | I | I |
| Writing secure code and tests | R | A | C | C | I | I |
| SAST and secret scanning tooling | I | I | C | A | R | I |
| Triage of scanner findings | C | C | R | A | I | I |
| Fixing findings within SLA | R | A | C | C | I | I |
| Dependency policy and registry rules | C | C | C | A | R | I |
| Approving new dependencies | R | A | C | C | I | I |
| Pipeline hardening | I | C | C | C | A/R | I |
| Threat models | R | A | R | C | C | I |
| Security exceptions | I | R | C | C | I | A |
| Incident response | R | R | C | A | R | I |
| Security training | R | I | C | A | I | R |
R responsible, does the work. A accountable, one per row, answers for the outcome. C consulted before. I informed after.
Triage and SLAs for findings
Raw scanner output is not a work queue. Triage turns it into a short list of real problems, each with an owner and a deadline. Severity alone is a poor guide: weigh whether the flaw is reachable, whether the system is exposed, and whether it is being exploited, using the CISA KEV catalog and EPSS scores.
- Deduplicate the same issue reported by several tools or in several branches.
- Confirm it is real and reachable. Discard with a reason if not, and feed that back to the rule.
- Rate with context: exposure, data, exploitation in the wild.
- Route to the owning team's backlog, not a separate security tracker nobody reads.
- Verify the fix, and close the loop with whoever reported it.
| Priority | Typical meaning | Fix within |
|---|---|---|
| P0 | Exploited in the wild (KEV listed) and exposed, or a live leaked secret | Hours to 2 days |
| P1 | Critical or high, reachable, internet facing | 7 days |
| P2 | High but internal, or medium and exposed | 30 days |
| P3 | Medium, internal, hard to reach | 90 days |
| P4 | Low, hardening | Planned work |
Example starting points. Set yours with both teams, publish them, and report against them.
Know who is affected in minutes
For a malicious or vulnerable package, the first question is which applications pulled it. A registry that records every download per token and application answers that immediately, see SBOMs of what was actually pulled and the kill switch.
Reducing false positives
Every wrong finding teaches developers that findings can be ignored. Treat noise as a defect in the security program, owned by the security team.
- Start from a baseline and block only on new findings in the change.
- Block merges only on high confidence rules. Everything else is a comment, not a gate.
- Let developers mark a finding as wrong in one click, with a reason, and review those weekly.
- Track false positive rate per rule. Fix or retire the worst ones.
- Use reachability and exposure to rank dependency findings, not the CVSS base score alone.
- Security triages before routing, so teams receive confirmed problems.
A free SAST and code review tool such as Git Code Review can run on every pull request; the practices above apply whichever scanner you use.
Exceptions and waivers, with an expiry
Sometimes the right call is to accept a risk for now. That is fine when it is explicit, owned and temporary. An exception with no end date is a permanent hole with paperwork.
id: EXC-2026-041
finding: vulnerable version of an XML parser in billing-api
reason: fixed release needs a major upgrade, planned for Q4
compensating: XML endpoint disabled at the gateway
risk_owner: eng manager, billing
approved_by: appsec lead
created: 2026-09-19
expires: 2026-12-18 # 90 days at most, then re-decide
review: monthly in the shared metrics meeting
The same applies to dependencies: when a package is blocked, developers need a fast, visible way to ask for it, or they will find a way around the block. ForgeRepo™ has a request and approval flow for exactly that.
Security in sprint planning
- Security work lives in the team's own backlog, sized and prioritized like everything else.
- Stories that touch auth, payments, personal data or new external inputs carry security acceptance criteria, for example from OWASP ASVS.
- Write abuse cases next to use cases: "as an attacker, I change the invoice id in the URL".
- The definition of done includes: tests for the authorization rules, no new high findings, dependencies reviewed.
- Reserve a fixed slice of each sprint for security debt, so SLA work does not fight features every time.
Blameless incident reviews
After an incident, ask what made the mistake possible and easy, not who made it. People who fear blame hide near misses, and near misses are the cheapest lessons you get. Google's postmortem culture chapter is a good template.
- A timeline from first signal to resolution, written together by security and the owning team.
- Contributing factors: missing guardrails, confusing defaults, alerts nobody saw.
- Actions that change the system (a paved road, a check, a default), each with an owner and a date.
- Shared widely, including what went well.
Anti-patterns, and what to do instead
A penetration test or review a week before release finds design problems that are now expensive to fix, and the release ships with them anyway.
Instead: Threat model at design time, scan in the pull request, and keep the late test for what only a person can find.
A spreadsheet of 4,000 findings lands on a team with no context, no priority and no owner.
Instead: Triage first, deduplicate, route a short confirmed list into the team's backlog with an SLA.
Blocked packages downloaded by hand, checks disabled "for now", secrets pasted to get a build green.
Instead: Find out why. Usually the control is slow or has no path to yes: add a request flow and fix the friction.
A title, a chat channel, and the same full feature load as before.
Instead: Protected time agreed with the manager, and recognition in reviews.
Waivers granted once and never revisited, until the incident.
Instead: Every exception expires and comes back for a decision, with its compensating control checked.
Developers see security as someone else's job, and security has no say in how things are built.
Instead: Clear shared ownership, written down, reviewed together.
A maturity model
Use it to agree where you are today and pick the next step, not to score teams against each other. For a complete, well tested model, see OWASP SAMM.
| Area | 1. Ad hoc | 2. Repeatable | 3. Defined | 4. Measured |
|---|---|---|---|---|
| Ownership and culture | Security is the security team's problem | Champions in some teams | Written RACI, champions in every team | Shared goals reviewed monthly by both teams |
| Code scanning | Occasional manual scans | SAST in CI on main branches | SAST and secret scanning on every pull request, new findings only | Rules tuned by false positive rate, findings mostly caught before merge |
| Dependencies | Installed straight from public registries | Lockfiles committed, dependency scanning | All installs through a registry firewall, reserved internal names | Cooling off, provenance checks, and "who pulled it" answered in minutes |
| Pipelines | Long lived keys, shared runners | Secrets in the CI store, some pinning | OIDC, pinned actions, scoped tokens, ephemeral runners | Signed artifacts with provenance, verified at deploy (SLSA Build L2 or L3) |
| Findings and SLAs | No SLAs, backlog grows | SLAs exist on paper | Triage, routing and SLAs in the team backlog | SLA performance reported and improving |
| Threat modeling | Never, or after incidents | For big projects, by security | For every new service, led by teams | Findings from models tracked to closure and fed into paved roads |
| Exceptions | Informal, permanent | Recorded | Owned, with compensating controls and expiry | Few, reviewed, none expired |
| Learning from incidents | Blame, or silence | Reviews for major incidents | Blameless reviews with owned actions | Actions change paved roads and defaults, shared across teams |
A 30/60/90 day plan
For a security lead and an engineering lead starting this together. Small, visible steps first.
Days 1 to 30 see and agree
- Inventory repositories, pipelines, build servers and where packages come from.
- Agree three to five shared metrics and take a baseline.
- Write the first RACI and the SLA table, and publish them.
- Ask for a champion in each team, with time agreed.
- Turn on secret scanning everywhere, and rotate anything it finds.
- Quick pipeline wins: read only default tokens, no
pull_request_targeton untrusted code.
Days 31 to 60 pave the road
- SAST on every pull request, baselined, blocking only new high confidence findings.
- Route all package installs through a registry firewall, and enforce lockfile installs in CI.
- Pin third party actions and images, and let a bot keep the pins current.
- Move the first deploy pipelines to OIDC.
- Run the first threat modeling sessions with two teams.
- Start the triage rotation and the exception register.
Days 61 to 90 measure and spread
- First monthly metrics review, together, with actions.
- Retire or fix the noisiest scanner rules.
- Ship a shared CI template and base image as the paved road.
- Ephemeral runners and provenance for the most critical service.
- A blameless review of one real incident or near miss.
- Re-rate the maturity model and pick the next quarter's two areas.
For the history that makes the case to leadership, see ten years of supply chain attacks and software supply chain security.
A paved road for every dependency
One registry for npm, PyPI, Docker, NuGet, Maven and more, with policy both teams can see, a request flow instead of workarounds, and a record of who pulled what. ForgeRepo™ is free and self hosted.