Dev.to Security 🔐 Cybersecurity 👁 0 📖 5 min read

Plumbing CNAPP Findings Into the Way Engineers Already Work

You can buy a very good cloud-native application protection platform and still get almost nothing from it. The failure is rarely detection. It is delivery: findings sit in a console that engineers never open, tickets lan

Plumbing CNAPP Findings Into the Way Engineers Already Work

Padlock over a cloud network diagram representing security checks in a delivery pipeline

You can buy a very good cloud-native application protection platform and still get almost nothing from it. The failure is rarely detection. It is delivery: findings sit in a console that engineers never open, tickets land on a platform team that did not write the code, and a noisy pipeline check gets bypassed within a week.

This post is about the integration layer around the platform. It is mostly platform-engineering work, and it is the difference between a security product and a security practice. For the product side, including architectures and vendor categories, see our full CNAPP tools guide.

All snippets below are illustrative. Adapt names, providers and policy engines to your stack.

1. Ownership is a schema, not a spreadsheet

Correlation engines can tell you that a public bucket, a vulnerable image and an over-privileged role form one path to customer data. They cannot tell you who should fix it unless the resources say so.

Make ownership a required attribute of every resource and enforce it where resources are born: in infrastructure-as-code.

A simple Terraform pattern is to set default tags at the provider and validate the inputs:

# Illustrative: enforce ownership tags at the provider level
variable "owner_team" {
  type = string
  validation {
    condition     = can(regex("^team-[a-z0-9-]+$", var.owner_team))
    error_message = "owner_team must look like team-<name>."
  }
}

variable "service" {
  type = string
}

provider "aws" {
  default_tags {
    tags = {
      owner_team  = var.owner_team
      service     = var.service
      environment = terraform.workspace
      repo        = "github.com/acme/payments-api"
    }
  }
}

Default tags catch most cases, but not resources created outside that provider block or by hand. Back it up with a policy check in CI (OPA/Conftest, Sentinel, or your CNAPP's own IaC rules) that fails a plan containing untagged resources, and a periodic report from the platform listing untagged live resources by account.

The repo tag matters more than it looks. It is what lets a runtime finding be traced back to the repository and pull request that introduced it.

2. PR checks: block few, warn most

The fastest way to lose engineering goodwill is a scanner that blocks a hotfix over a low-risk rule. The fastest way to lose security value is a scanner that never blocks anything.

Split policies into two tiers:

  • Blocking: a short, high-confidence list. Public exposure of data stores, wildcard admin permissions, disabled encryption on sensitive stores, secrets in code.
  • Warning: everything else, surfaced as PR annotations with a link to the remediation guidance.

A CI job might look like this:

# Illustrative GitHub Actions job. Replace the scanner CLI with your platform's.
iac-security:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - name: Scan Terraform (warn on all rules)
      run: |
        cnapp-cli iac scan ./infra \
          --output sarif --out results.sarif \
          --exit-code 0
    - name: Enforce blocking policy set only
      run: |
        cnapp-cli iac scan ./infra \
          --policy-set blocking-v1 \
          --exit-code 1
    - name: Upload annotations
      uses: github/codeql-action/upload-sarif@v3
      with:
        sarif_file: results.sarif

Version the blocking set (blocking-v1, blocking-v2) and promote rules into it deliberately, after they have run in warn mode long enough for you to see their false-positive rate. Start image scanning the same way: annotate everything, fail only when a critical vulnerability is in a package that is actually reachable, if your platform exposes that signal.

Developer workstation showing pipeline checks and security annotations

3. Route findings to trackers, not inboxes

Once resources carry owner_team and repo, routing becomes deterministic. Pull prioritised findings from the platform's API on a schedule and push them into whatever tracker each team already uses.

Three rules keep this from becoming spam:

Route attack paths, not raw findings. A path with four links should be one parent issue with child tasks, each assigned to the owner of that link. Whoever can break the cheapest link first should see that.

Deduplicate with a stable key. Hash something like finding_type + resource_id + rule_id and store it on the ticket. On each sync, update existing tickets instead of creating new ones, and close them automatically when the platform reports the finding resolved.

# Illustrative dedup key for a sync job
import hashlib

def dedup_key(finding):
    raw = f"{finding['type']}|{finding['resource_id']}|{finding['rule_id']}"
    return hashlib.sha256(raw.encode()).hexdigest()[:16]

Fall back loudly. Findings on untagged resources should go to a single triage queue owned by platform engineering, and that queue's size should be a visible metric. It is your tagging debt, measured.

4. Risk exceptions that expire

Engineers will sometimes have a legitimate reason not to fix something now: a vendor dependency, a migration already scheduled, a compensating control. If the only options are "fix" or "ignore", they will ignore, and nobody will know.

Give them a third option that is auditable and temporary. Keep exceptions as code, reviewed like any other change:

# Illustrative: security/exceptions.yaml
- id: EXC-0142
  rule: storage-public-listing
  resource: arn:aws:s3:::acme-staging-artifacts
  reason: Public docs mirror; bucket holds no credentials. Migration tracked in PLAT-881.
  approved_by: team-platform-lead
  expires: 2026-12-01

A nightly job syncs these to the platform's suppression API and re-opens the ticket automatically after expires. A CI check can reject exceptions with no expiry or an expiry beyond an agreed maximum.

5. Measure the plumbing, not just the risk

A few numbers tell you whether the integration layer works:

  • Share of findings routed automatically to an owner (versus the fallback queue)
  • Share of issues caught at PR time rather than in running infrastructure
  • Median time from finding to merged fix, by severity
  • Count of active exceptions, and how many expired without action

None of this is exotic. It is the same discipline you would apply to any production system, which is the point. When we build SaaS platforms, controls that live in code and pipelines scale with the team; controls that live in a console depend on someone remembering to look.

Frequently Asked Questions

Where should ownership tags be enforced?

At creation time in infrastructure-as-code, using provider-level default tags plus a CI policy check that fails plans with untagged resources. A recurring report of untagged live resources catches anything created outside the pipeline.

Which security rules should block a pull request?

Only a small set of high-confidence, high-impact rules such as public data exposure, wildcard administrator permissions, disabled encryption on sensitive stores and committed secrets. Everything else should warn with remediation guidance so delivery is not stalled.

How do we stop security tickets from duplicating?

Generate a stable key from the finding type, resource identifier and rule, store it on each ticket, and update or close existing tickets on every sync instead of creating new ones.

Should findings be routed individually or as attack paths?

Route correlated attack paths as a parent issue with a task per link, each assigned to its owner. That keeps context together and lets teams break the quickest link first.

How should teams handle risks they cannot fix yet?

Use exceptions stored as code with a reason, an approver and an expiry date. Sync them to the platform's suppression mechanism and reopen the underlying ticket automatically when the exception lapses.

Architectures, platform categories and AI features are covered in the full guide: CNAPP Tools in 2026.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.