Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Dev-Sec collaboration and feedback loops

By updated

Improve this page

Take a typical case: an e-commerce team of 45 developers where every security scan triggers a wave of frustration. Alerts pile up, developers work around them, the security team feels ignored, and the time to fix vulnerabilities is counted in weeks. The problem is neither the tool nor the people: it is the lack of structured Dev-Sec collaboration.

This page is for tech leads, security champions and platform engineers who want to organise this collaboration rather than endure it. It covers three pillars: a blameless culture to handle incidents without a blame hunt, automated feedback loops (IDE, merge request) to shorten the delay between error and fix, and clear communication channels with explicit response times.

What you will learn

  • Diagnose the systemic causes of friction between developers and the security team.
  • Establish a blameless culture with structured, non-punitive postmortems.
  • Design feedback loops that catch problems before merge rather than in production.
  • Structure communication channels (asynchronous, synchronous, escalation) with suitable response times.
  • Measure collaboration itself, not just the number of vulnerabilities.

This lesson assumes an organisation that is already structured: identified development teams with clear roles, and a security team that exists, even without a formal programme. The Security Champions programme provides the relays on the development side that keep the channels described here alive, and team training (in French) the shared skills foundation.

Where does friction between developers and security come from?

Friction between developers and security teams is not a personality clash: it is a systemic problem, born from goals perceived as contradictory and incompatible communication styles. Both teams aim for the same result, a quality product, but do not measure their success the same way.

Developers are assessed on delivery velocity and user satisfaction, security teams on risk reduction and compliance. Without a collaboration structure, these indicators create natural tension. Two recent surveys put figures on the problem:

IndicatorValueSource
Time lost each week to inefficient processes7 hoursGitLab Global DevSecOps Report, published November 2025, 3,266 respondents
Organisations running at least one service with a known exploitable vulnerability87 %Datadog State of DevSecOps 2026
"Critical" vulnerabilities that stay critical once runtime context is applied18 %Datadog State of DevSecOps 2026

These figures describe the same vicious circle: when almost everything is labelled "critical", nothing really is. Developers get tired, work around alerts, and real vulnerabilities drown in the noise. To break out, you must act at the same time on culture (how we react to errors), processes (how we communicate) and tools (how we automate feedback).

How do you establish a blameless culture?

A blameless culture comes from aviation: pilots can report their errors without fear of sanction, because fear of punishment pushes people to hide problems instead of solving them. The same principle applies to software security.

A blameless culture does not mean that anything goes. It means that the default response to an incident is not "who is responsible?" but "what allowed this error?". You look for a process to improve, not a culprit to punish. The diagram compares the two reactions to the same vulnerability.

Faced with a vulnerability in production, the traditional culture looks for a culprit, sanctions and pushes people to hide errors; the blameless culture looks for what allowed the error, documents a postmortem and improves processes and guardrails.Blameless cultureWhat allowed the error?Documented postmortemImproved processes and guardrailsTraditional cultureWho caused the problem?Individual sanctionErrors hidden out of fearVulnerabilityfound in production
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

In a traditional culture, the guilty developer gets a warning, mostly learns to hide errors better, and the problem happens again elsewhere. In a blameless culture, the same vulnerability triggers a systemic analysis: why did the tests not catch it? Why did code review let it through? Which automated guardrail was missing? The incidents and postmortems lesson details this mechanism beyond security alone.

Putting blameless principles in place

A blameless culture cannot be decreed: it is built through concrete, repeated practices, carried by management and checked in practice. The following steps give the usual order.

  1. Officially announce the change of approach

    Management explicitly announces that security errors will no longer be treated as individual faults, then repeats the message. A single email is not enough: managers relay it in their teams, and the first real situations must demonstrate the change.

  2. Train managers in facilitation

    Managers are the first who need to change their reflex. Faced with an incident, their first question becomes "what happened?" and not "who did this?". The training includes role plays and ready-to-use phrasing for difficult moments.

  3. Document and share postmortems

    Each significant incident leads to a written postmortem, accessible to the whole organisation. This transparency shows that the company owns its errors collectively and learns from each one.

  4. Value the discovery of problems

    When someone reports a vulnerability they introduced themselves, thank them publicly. This positive reinforcement encourages others to do the same.

  5. Measure the cultural change

    Regular anonymous surveys check that teams actually perceive the change. Key indicator: the share of developers who feel comfortable reporting a security error.

Structuring blameless postmortems

The postmortem is the central tool of a blameless culture. A postmortem that leads to no action and no learning is just a window-dressing exercise. The YAML template below keeps a factual timeline, an analysis centred on processes and actions assigned to roles, never to people.

blameless-postmortem.yaml
# Blameless postmortem template (fictional identifiers)
metadata:
incident_id: "SEC-2026-042"
date: "2026-02-10"
severity: "high"
facilitator: "payments-security-champion"
duration_meeting: "90min"
# Factual timeline: no attribution of fault
timeline:
- time: "2026-02-10 09:15"
event: "SCA alert on a critical CVE in production"
facts: "Vulnerable transitive dependency detected in service-payment"
- time: "2026-02-10 09:30"
event: "Team notified on the security alerts channel"
facts: "Notification delay: 15 minutes"
- time: "2026-02-10 10:45"
event: "Fix deployed to production"
facts: "Dependency updated, time to fix: 90 minutes"
# Systemic analysis: processes, not people
analysis:
what_happened: |
A vulnerable transitive dependency came in with the payment SDK update.
The nightly SCA scan detected it 3 days after the merge.
why_it_happened:
- "The SCA scan ran at night, not on merge requests"
- "The dependency was transitive (2 levels), absent from package.json"
- "The SDK changelog did not mention the dependency change"
what_went_well:
- "Automatic detection worked"
- "Escalation process followed"
- "Fix deployed in under 2 hours"
# Improvement actions: assigned to roles, not individuals
action_items:
- id: "AI-001"
action: "Add the SCA scan to the merge request pipeline"
owner: "platform-team"
deadline: "2026-02-17"
- id: "AI-002"
action: "Alert on any new transitive dependency"
owner: "security-team"
deadline: "2026-02-24"
metrics:
time_to_detect: "72h"
time_to_remediate: "90min"
customers_impacted: 0

The postmortem facilitator reframes any discussion that drifts toward finding a culprit, with phrases such as "let's focus on what made this situation possible" or "which process would have prevented this error?". This role is learned: without it, the best document template turns back into a trial.

How do you shorten feedback loops?

A feedback loop is the time between the moment a developer introduces a security problem and the moment they learn about it. The shorter this delay, the simpler and cheaper the fix: this is the shift-left principle applied to communication.

Think of a thermostat that reacted 24 hours late: impossible to keep a stable temperature. Security is the same: instant feedback allows an immediate fix, late feedback arrives when the developer has lost the context. The diagram places the pipeline's feedback points and their typical delay.

Pipeline feedback points: IDE (instant), pre-commit (seconds) and merge request (minutes) before merge, with context still fresh; build (minutes) and deployment (hours) after merge, with a costlier fix.After merge: costlier fixBefore merge: context stillfreshIDEinstantPre-commitsecondsMerge requestminutesBuildminutesDeploymenthours
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

A frequent internal target is to detect 80 % of problems before merge, in the IDE or the merge request. It is a team goal, not a published standard: what matters is the trend, measured by the stage at which each vulnerability is detected.

Feedback in the IDE

The most effective feedback arrives in the development environment, before the first commit. Security extensions flag problems in real time, like a spell checker flags a typo. For VS Code, an extensions.json file recommends the extensions to the whole team:

.vscode/extensions.json
{
"recommendations": [
"semgrep.semgrep",
"snyk-security.snyk-vulnerability-scanner"
]
}

The configuration favours relevance over exhaustiveness: a developer flooded with false positives turns the extension off. Start with high-confidence rules, hide low severity, and exclude code that never reaches production. The keys below are the ones declared by the Semgrep (semgrep.scan.*) and Snyk (snyk.severity) extensions:

.vscode/settings.json
{
"semgrep.scan.configuration": ["p/security-audit", "p/owasp-top-ten"],
"semgrep.scan.exclude": ["tests", "vendor"],
"snyk.severity": {
"critical": true,
"high": true,
"medium": true,
"low": false
}
}

Feedback on the merge request

The second feedback point is the merge request, the last chance to catch a problem before the main branch. Feedback there must be contextual: results show up in the merge request security widget rather than in a 50-line report, and only cover what the merge request introduces.

The GitLab CI job below runs Semgrep in differential mode: --baseline-commit only reports results absent from the base commit, and --gitlab-sast produces the report GitLab displays. Tested with Semgrep 1.178.0: on a repository containing an old and a new defect, the full scan reports both, the differential scan only the new one, in GitLab SAST format 15.0.4.

.gitlab-ci.yml
semgrep_mr:
stage: test
image: semgrep/semgrep:1.178.0@sha256:32e459968daabe7ab86968184a29109b9564aa00392401156f9788452b42786b
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
GIT_DEPTH: "0" # full history: the base commit must be present
script:
- git config --global --add safe.directory "$CI_PROJECT_DIR"
- semgrep scan --config p/default --metrics off
--baseline-commit "$CI_MERGE_REQUEST_DIFF_BASE_SHA"
--gitlab-sast --output gl-sast-report.json
artifacts:
reports:
sast: gl-sast-report.json

The Semgrep guide (in French) details writing custom rules and the public rule registries.

Handling false positives without losing trust

A false positive is an alert that does not match a real vulnerability: an overly generic rule, a special case the tool does not understand, a detection in test code. False positives are the leading cause of alert fatigue, the kind that pushes developers to ignore every notification. An explicit handling path is required.

StepWhoWhat happensIndicative delay
ReportDeveloperComment in the merge request with the technical justificationImmediate
TriageSecurity championChecks the justification and the rule documentation, then decides: false positive, true positive or escalation4 business hours
ReviewSecurity teamComplex cases: application context, global rule adjustment24 business hours
SuppressionDeveloperDocumented suppression, with the decision referenceAfter approval

With Semgrep, suppression takes two forms. A specific line is neutralised by a nosemgrep comment that names the rule; a whole path is excluded in a .semgrepignore file, which uses .gitignore syntax. Naming the rule avoids hiding other detections on the same line, and the decision reference makes the suppression auditable:

src/utils/internal-redirects.js
// Redirect to a fixed list of internal URLs, never user input.
// Decision SEC-2026-042, approved by the security team.
res.redirect(INTERNAL_ROUTES[name]); // nosemgrep: javascript.express.security.audit.express-open-redirect.express-open-redirect
.semgrepignore
# Test code and fixtures: never deployed
tests/
fixtures/

Enriching alert context

A raw "SQL Injection detected at line 42" alert does not help a junior developer understand the risk or fix it. Contextual enrichment adds an accessible explanation, the business impact and the fix steps. The file below is an illustrative in-house format: most vulnerability management platforms let you attach this kind of sheet to a rule.

alert-enrichment.yaml
# Enrichment sheet per vulnerability type (in-house format)
sql_injection:
severity: "critical"
explanation: |
An attacker can run arbitrary SQL queries on the database:
read, modify or delete all data.
business_impact:
- "Customer data theft (GDPR: fine up to 4 % of worldwide annual turnover)"
- "Corruption or loss of production data"
remediation_steps:
- "Trace the data flow from input to query"
- "Replace concatenation with a parameterised query"
- "Validate input type and format upstream"
example: |
# Vulnerable
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# Fixed
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
reference: "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"

Which communication channels should you set up?

Dev-Sec collaboration does not rest on tools alone: design questions and trade-offs between risk and delay need human exchanges. These exchanges are structured by urgency level, each with its channel and its response time, as the diagram shows.

Three levels of Dev-Sec channels: asynchronous (questions channel, merge requests, tickets, answer within 24 business hours), synchronous (security office hours, design review, 2 h a week), escalation (security on-call, incident room, answer within 15 min).complex topiccritical emergencyAsynchronousquestions channel, merge requests, ticketsanswer within 24 business hoursSynchronoussecurity office hours, design review2 h a weekEscalationsecurity on-call, incident roomanswer within 15 min
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

Using the wrong channel creates friction: an urgent message lost in a general channel, or a simple question that mobilises the whole security team in a meeting. The tabs detail the uses and good practices of each level.

For general questions, clarification requests and non-urgent discussions, with an answer expected within 24 business hours:

  • a #security-questions channel open to the whole organisation;
  • merge request comments for anything related to code;
  • tickets for formal requests that need follow-up.

Include the full context in the first message, use threads and mention the right people rather than the whole channel.

Running security office hours

Security office hours are a recurring slot where the security team answers developers live. Inspired by university office hours, this format gives access to expertise without the weight of a ticket or a formal meeting.

The format that works best fits in a few rules: 2 hours a week in the same slot, one or two security engineers on rotation, developers who drop in without registering, at most 20 minutes per question and a visible queue. The last minutes are used to note recurring questions, which become documentation.

Track attendance, question types and satisfaction. If nobody comes, the slot is badly chosen or its existence is poorly known: it is a signal to act on, not proof that office hours are useless.

How do you build security into daily workflows?

Dev-Sec collaboration must not be a parallel process: it fits into developers' existing workflows. Three anchor points come back everywhere: a shared dashboard, the merge request and notifications.

A collaboration dashboard

A collaboration dashboard shows what interests both teams at once: not just the number of vulnerabilities, but the health of the collaboration. The panels below can be built in any visualisation tool (Grafana, Metabase) from the data of your scanners and your messaging tool.

PanelQuestion it answersIndicative thresholds
Median time to fixDo we fix quickly?green under 24 h, red beyond 7 days
Share of reported false positivesAre the rules well tuned?green under 10 %, red beyond 40 %
Questions unanswered for 24 hCan the security team be reached?green at 0, red beyond 5
Detection stage per weekIs shift-left progressing?trend toward 80 % before merge

A checklist in the merge request

The merge request is the ideal moment for security review: the code is ready, the context is fresh, the discussion is natural. A checklist in the merge request template recalls the points to check without slowing the flow. In GitLab, templates go in .gitlab/merge_request_templates/:

.gitlab/merge_request_templates/Security.md
## Security checklist
### Data and input
- [ ] User input is validated (type, format, length)
- [ ] Sensitive data is not logged
- [ ] SQL queries are parameterised
### Authentication and authorisation
- [ ] Endpoints that require authentication are protected
- [ ] Authorisation checks are present
- [ ] No secret is hard-coded
### Dependencies
- [ ] No new dependency with a known CVE
- [ ] Every added dependency is justified and maintained
Security review needed? Add the `security-review-needed` label.

Notifications that reach the right person

A security notification that arrives at the wrong time, in the wrong place or without context gets ignored. The Python script below routes each result by severity and time: a critical one goes straight to the incident channel with a mention of the on-call group, a high one goes to the team channel during business hours, the rest joins a daily digest.

Two details change everything. An "@group" mention written as plain text notifies nobody: Slack only alerts a group through the <!subteam^ID> syntax, with the group's identifier. And business hours are computed in an explicit time zone, not the server's own. The routing logic was tested against a fake Slack client on seven cases (critical at night, high on a weekday, high on Saturday, low severity).

security_notification_bot.py
"""Route security alerts to Slack based on severity and time."""
import os
from dataclasses import dataclass
from datetime import datetime, time
from typing import Optional
from zoneinfo import ZoneInfo
from slack_sdk import WebClient
TIMEZONE = ZoneInfo("Europe/Paris")
# Repository -> team channel and on-call group. The group identifier
# (S...) is read in Slack: a plain-text "@group" mention notifies
# nobody, only the <!subteam^ID> syntax does.
TEAMS = {
"payment-service": {"channel": "#team-payments", "oncall": "S0123PAY45"},
"user-service": {"channel": "#team-identity", "oncall": "S0456IDN78"},
}
SECURITY_ONCALL = "S0789SEC01"
@dataclass
class Finding:
id: str
severity: str # critical, high, medium, low
title: str
repository: str
file_path: str
line_number: int
detection_stage: str # ide, mr, build, deploy
remediation_url: Optional[str] = None
def business_hours(now: datetime) -> bool:
"""Monday to Friday, 9 am to 6 pm, Paris time."""
return now.weekday() < 5 and time(9) <= now.time() <= time(18)
def message(f: Finding) -> list:
blocks = [
{"type": "header", "text": {"type": "plain_text",
"text": f"[{f.severity.upper()}] {f.title}"}},
{"type": "section", "fields": [
{"type": "mrkdwn", "text": f"*Repository:* {f.repository}"},
{"type": "mrkdwn", "text": f"*File:* `{f.file_path}:{f.line_number}`"},
{"type": "mrkdwn", "text": f"*Detected at:* {f.detection_stage}"},
]},
]
if f.remediation_url:
blocks.append({"type": "section", "text": {
"type": "mrkdwn", "text": f"<{f.remediation_url}|Fix guide>"}})
return blocks
def route(f: Finding, now: datetime) -> Optional[tuple]:
"""Return (channel, text) to post right away, or None for the digest."""
team = TEAMS.get(f.repository, {})
if f.severity == "critical":
group = team.get("oncall", SECURITY_ONCALL)
return "#security-incidents", f"<!subteam^{group}> critical vulnerability"
if f.severity == "high" and business_hours(now):
return team.get("channel", "#security-alerts"), "New high vulnerability"
return None # high out of hours, medium and low: 9 am digest
def notify(client: WebClient, f: Finding, digest: list) -> None:
target = route(f, datetime.now(TIMEZONE))
if target is None:
digest.append(f)
return
channel, text = target
client.chat_postMessage(channel=channel, text=text, blocks=message(f))
if __name__ == "__main__":
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
digest: list = []
notify(client, Finding(
id="VULN-0042", severity="critical", title="SQL injection in search",
repository="user-service", file_path="src/controllers/UserController.java",
line_number=142, detection_stage="mr"), digest)

Sending the 9 am digest (a scheduled job that empties the list) and storing pending results depend on your infrastructure: they are deliberately left out of the script, which only shows the routing logic.

How do you reduce day-to-day friction?

Beyond processes and tools, collaboration relies on hunting down day-to-day friction. Every obstacle, even a small one, erodes goodwill and pushes developers to work around security controls. The table lists the most frequent ones and their remedy.

FrictionEffectRemedy
Scans too slowSlower pipeline, late feedbackDifferential scan on the merge request
Too many false positivesAlert fatigue, ignored alertsRule tuning, justified suppressions
Outdated documentationBad practices repeatedQuarterly review, documentation close to the code
Inaccessible expertiseBlockers, risky decisionsSecurity office hours, security champions
Manual approvalsBottleneck, workaroundsAutomation with dated exceptions

This list is not fixed: each organisation has its own friction points. What matters is a regular ritual (quarterly retrospective, anonymous survey) that surfaces them before they turn into silent workarounds.

A self-service catalogue

Security self-service lets developers handle common requests themselves without waiting for the security team, which can then focus on complex topics. The catalogue below can be implemented in a developer portal (Backstage, for example) or in simple triggerable pipelines; delays are targets to adjust.

ServiceAutomation levelWho can trigger itTarget delay
Rotation of a compromised or expired secretFullAny developerUnder 5 minutes
Exclusion of a test or generated code pathAutomatic for standard categoriesTech leadImmediate
False positive reportApproval by a championAny developerUnder 4 hours
Temporary exception on a vulnerable dependency, dated (30 days at most) with a fix planApproval by a championTech leadUnder 4 hours
Security review request for a featureManualAny developer2 to 5 days depending on the level

How do you measure collaboration effectiveness?

Dev-Sec collaboration indicators differ from pure security indicators: they measure the quality of the interaction between teams, not just the number of vulnerabilities. The targets in the table are internal starting benchmarks, to adjust.

IndicatorIndicative targetMeasurement
Time to first answer on the questions channelUnder 4 hMedian time to first answer
Office hours attendanceOver 30 % of teams per monthDistinct teams that came at least once
Cross satisfactionAverage score of 7 out of 10 or moreQuarterly survey, in both directions
False positives handled on timeOver 90 % within 24 hShare of reports decided on time
Detection before mergeTrend toward 80 %Share of vulnerabilities detected in the IDE or merge request
Time to fixUnder 7 days (high), under 30 days (medium)From report to resolution

The cross-satisfaction survey is the most telling indicator. Two questions are enough, scored from 1 to 10: "How easy is it to work with the security team?" and "How easy is it to work with the development teams?". Track their quarterly trend rather than their absolute value.

These goals take on particular weight with the 2025 DORA report, renamed "State of AI-assisted Software Development". Its central finding matches this lesson: generative AI speeds up delivery but amplifies the instability of teams whose culture and collaboration are already fragile. Good Dev-Sec collaboration is no longer a comfort, it determines whether AI can be adopted without multiplying incidents.

What rollout plan over 12 weeks?

Improving Dev-Sec collaboration is a cultural change that takes time. The plan below spreads the work over 12 weeks, two weeks per workstream, with a measurement at the start and at the end to objectify progress.

  1. Weeks 1-2: diagnosis and announcement

    Measure the starting point (time to fix, cross satisfaction, attendance). Officially announce the initiative. Spot possible quick wins.

  2. Weeks 3-4: blameless culture

    Train managers in facilitation. Run the first postmortem with the new template and share it widely.

  3. Weeks 5-6: communication channels

    Create the dedicated channels, launch security office hours, announce response times.

  4. Weeks 7-8: automated feedback

    Recommend the IDE extensions, add the differential scan on merge requests, set up the false positive path.

  5. Weeks 9-10: self-service and dashboard

    Open two or three self-service services and the collaboration dashboard.

  6. Weeks 11-12: measurement and adjustment

    Measure the indicators again, rerun the satisfaction survey, choose next quarter's adjustments.

Key points

  • Treat each incident as a systemic problem, not an individual fault: a blameless culture brings errors to light instead of hiding them.
  • A useful postmortem leads to actions assigned to roles, otherwise it is theatre.
  • Shorten feedback loops: IDE extensions, differential scan on the merge request, with an internal target of 80 % detection before merge.
  • Handle false positives through an explicit path and named, justified nosemgrep suppressions: they are the leading cause of alert fatigue.
  • Give each type of question a channel and a response time (asynchronous, synchronous, escalation).
  • A Slack group mention only notifies through <!subteam^ID>: check that a critical alert really reaches the on-call group.
  • Measure collaboration itself (cross satisfaction, office hours attendance), not just vulnerabilities.

Knowledge check

Check that you have the essentials of this guide. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

FAQ: frequently asked questions

The questions below cover the most frequent doubts about blameless culture, feedback loops, false positives and security office hours.

External resources

The chapter of Google's SRE book and Etsy's article remain the founding texts of the blameless postmortem; the GitLab and Datadog reports provide the figures quoted in this lesson.

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn