AI-Powered Security Scanning is a continuous, automated process that identifies vulnerabilities, misconfigurations, and threats across infrastructure, code, and runtime environments using machine learning models trained on historical security data. It matters when security teams need to detect subtle, evolving attack patterns—such as zero-day exploits, lateral movement, or anomalous API usage—before they cause breaches, especially in cloud-native or microservices architectures with frequent deployments.

Onboarding a New Codebase

To begin AI-powered scanning, the first task is to ingest source code and build artifacts into the scanning pipeline. The scanning engine expects a scan.yml configuration file at the root of the repository, with the following keys:

scan:
  target: "main"
  scan_types:
    - static
    - dynamic
    - container
  include:
    - "src/"
    - "docker-compose.yml"
  exclude:
    - "tests/"
    - "docs/"
  models:
    - "sast-2023-q3"
    - "dast-2023-q2"
  threshold: 0.75

The target field specifies which branch or tag to scan. scan_types lists the kind of analysis to run: static (SAST), dynamic (DAST), and container (image-based analysis). include and exclude filter paths before scanning. models references pre-trained models used for detection, and threshold sets the minimum confidence score for a finding to be considered actionable.

The scanning engine supports git-based triggers and can be invoked via scannet scan [email protected]:org/project.git --branch=develop.

This command returns:

{
  "scan_id": "scn-7f9e3a2c",
  "status": "queued",
  "started_at": "2024-03-15T10:23:45Z",
  "repository": "github.com/org/project",
  "branch": "develop"
}

A scan is queued and processed asynchronously. The engine polls a message queue (via kafka or RabbitMQ) and processes each scan in parallel.

Running a Full Pipeline

After ingestion, the pipeline runs a sequence of scanning steps. Each step is defined in a pipeline.yaml file in the project root:

pipeline:
  stages:
    - name: "sast"
      type: "static"
      model: "sast-2023-q3"
      inputs:
        - "src/"
      outputs:
        - "reports/sast-results.json"
      config:
        rules:
          - "cwe-79"
          - "cwe-89"
        max_files: 500
        language: "python"
    - name: "dast"
      type: "dynamic"
      model: "dast-2023-q2"
      inputs:
        - "build/artifacts/app.war"
      outputs:
        - "reports/dast-results.json"
      config:
        target_url: "https://staging.example.com"
        crawler_depth: 5
        follow_redirects: true
    - name: "container-scan"
      type: "container"
      model: "container-2023-q4"
      inputs:
        - "images/app:latest"
      outputs:
        - "reports/container-results.json"
      config:
        vulnerabilities:
          - "cve-2023-1234"
          - "cve-2023-5678"
        analyze_layers: true

The pipeline executes stages in order. Each stage runs a command from the scanning engine’s CLI:

scannet run --pipeline=pipeline.yaml --context=dev

The engine logs to logs/pipeline-20240315-102345.log and emits structured events via systemd:

[Unit]
Description=AI Security Scanning Pipeline
After=network.target

[Service]
ExecStart=/usr/bin/scannet run --pipeline=pipeline.yaml --context=dev
Restart=always
User=scanner
Environment="SCANNER_LOG_LEVEL=info"
Environment="SCANNER_MODEL_DIR=/models"

[Install]
WantedBy=multi-user.target

Each stage produces a results.json file with this schema:

{
  "scan_id": "scn-7f9e3a2c",
  "stage": "sast",
  "model": "sast-2023-q3",
  "duration_seconds": 124.3,
  "findings": [
    {
      "id": "fnd-1a2b3c",
      "type": "vulnerability",
      "severity": "high",
      "confidence": 0.87,
      "location": {
        "file": "src/api/auth.py",
        "line": 42,
        "column": 15
      },
      "description": "SQL injection vulnerability in login endpoint",
      "recommendations": [
        "Use parameterized queries",
        "Validate all user input",
        "Add rate limiting"
      ],
      "metadata": {
        "cwe": "CWE-89",
        "owasp": "A1: Injection"
      }
    }
  ]
}

Detecting Anomalous Behavior

The scanning engine uses a model trained on historical runtime telemetry to detect anomalies in application behavior. Anomalies are triggered by deviations from expected patterns in logs, metrics, and traces.

The engine expects a anomaly.yml configuration in config/:

anomaly:
  data_sources:
    - type: "logs"
      path: "/var/log/app/*.log"
      format: "json"
      schema:
        timestamp: "ts"
        level: "level"
        message: "msg"
        service: "service"
        trace_id: "trace_id"
    - type: "metrics"
      endpoint: "http://prometheus:9090/api/v1/query"
      query: 'rate(http_requests_total{job="api"}[5m])'
      interval: "1m"
    - type: "traces"
      source: "jaeger"
      endpoint: "http://jaeger:14268/api/traces"
      min_duration_ms: 500
  models:
    - "anomaly-rt-2023"
    - "log-clustering-2023"
  thresholds:
    log_rate: 1.5
    trace_latency: 1.3
    error_rate: 0.8
  alerting:
    channels:
      - "slack"
      - "email"
    template: "anomaly_alert.tmpl"

The engine runs scannet analyze --config=anomaly.yml --start=2024-03-15T09:00:00Z --end=2024-03-15T11:00:00Z.

It produces a anomalies.json output:

{
  "anomaly_id": "anom-9c8b7a",
  "type": "latency_spike",
  "timestamp": "2024-03-15T10:22:33Z",
  "severity": "critical",
  "details": {
    "trace_id": "a1b2c3d4e5",
    "service": "payment-service",
    "latency_ms": 1432,
    "expected": 620,
    "z_score": 3.4,
    "causes": [
      {
        "model": "anomaly-rt-2023",
        "confidence": 0.92,
        "feature": "queue_length"
      },
      {
        "model": "log-clustering-2023",
        "confidence": 0.88,
        "pattern": "billing_batch_failed"
      }
    ]
  },
  "context": {
    "logs": [
      {
        "ts": "2024-03-15T10:22:31Z",
        "level": "error",
        "msg": "Failed to connect to payment gateway",
        "trace_id": "a1b2c3d4e5"
      }
    ],
    "metrics": {
      "http_requests_total": 1245,
      "queue_length": 98,
      "error_rate": 0.13
    }
  }
}

The engine can be scheduled via cron to run every 5 minutes:


*/5 * * * * /usr/bin/scannet analyze --config=anomaly.yml --start=$(date -Iseconds -d 'now - 5 minutes') --end=$(date -Iseconds)

Integrating with CI/CD

The scanning engine integrates with any CI/CD system via a standard scannet report command that formats findings into a common output format.

A GitHub Actions workflow uses scannet report to generate a summary:

name: Security Scan

on: [push]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run AI Scanning
        run: |
          scannet scan [email protected]:org/project.git --branch=main
          scannet run --pipeline=pipeline.yaml --context=ci
          scannet analyze --config=anomaly.yml --start=$(date -Iseconds -d 'now - 10 minutes')
      - name: Upload Results
        run: |
          scannet report --format=github --output=security-report.json
          echo "::set-output name=scan_id::$(cat security-report.json | jq -r '.scan_id')"
      - name: Comment on PR
        uses: peter-evans/create-or-update-comment@v4
        with:
          repository: ${{ github.repository }}
          issue-number: ${{ github.event.number }}
          body: |
            ## AI-Powered Security Scan Summary

            - **Scan ID**: ${{ steps.scan.outputs.scan_id }}
            - **Findings**: ${{ steps.scan.outputs.total_findings }}
            - **Critical Issues**: ${{ steps.scan.outputs.critical_count }}

            <details>
            <summary>Findings</summary>

            ```json
            ${cat security-report.json | jq -c '.findings'}

</details>


The `report` command accepts `--format=github`, `--format=slack`, `--format=markdown`, and `--format=json`. The `github` format generates a comment with a table of findings and links to detailed reports.

### Key Failure Modes

- **Model Version Mismatch**: When `pipeline.yaml` refers to a model named `sast-2023-q3`, but the scanning engine only has `sast-2023-q2`, the scan logs show:

WARNING: Model sast-2023-q3 not found. Using fallback model sast-2023-q2.


- **Missing Configuration Keys**: If `anomaly.yml` omits `thresholds`, the engine applies defaults but logs:

WARNING: Missing threshold for error_rate. Using default value 0.5.


- **Inconsistent Timestamps**: When logs come from multiple services with different time zones, the anomaly engine defaults to UTC. If timestamps are not in ISO 8601 format, it logs:

ERROR: Invalid timestamp format in logs. Expected ISO 8601, got "2024-03-15 10:22:31.123". Using fallback parser.


- **Failed Pipeline Stage**: A stage fails if the model output does not match the expected schema. The engine logs:

  ```json
  {
    "stage": "dast",
    "status": "failed",
    "error": {
      "type": "schema_mismatch",
      "expected": ["scan_id", "findings", "duration_seconds"],
      "actual": ["scan_id", "results", "duration"]
    }
  }
  • Missing Input Artifacts: When scannet run cannot find build/artifacts/app.war, it logs:
  ERROR: Input artifact build/artifacts/app.war not found. Check pipeline configuration and build step.

Maintaining Scanning Models

Models are stored in a shared storage backend (e.g., S3 or NFS) and versioned by timestamp. The engine discovers models via a models/ directory with this layout:

models/
├── sast-2023-q3/
│   ├── model.bin
│   ├── vocabulary.json
│   └── config.yaml
├── dast-2023-q2/
│   ├── model.bin
│   ├── vocabulary.json
│   └── config.yaml
└── anomaly-rt-2023/
    ├── model.bin
    ├── metadata.json
    └── config.yaml

Each config.yaml file defines hyperparameters used at inference time:

model:
  type: "transformer"
  input_size: 512
  hidden_layers: 8
  dropout: 0.3
  batch_size: 32
  learning_rate: 0.001

The scanning engine validates models at startup:

scannet validate-model --model=sast-2023-q3 --path=/models/sast-2023-q3/

It returns:

{
  "model": "sast-2023-q3",
  "valid": true,
  "issues": [
    "Missing vocabulary.json",
    "Incorrect input_size: expected 512, got 768"
  ]
}

If a model is invalid, the engine logs:

CRITICAL: Model sast-2023-q3 is invalid. Skipping in pipeline.

Upgrading the Scanning System

To upgrade scanning, the system uses a dual deployment strategy: old and new models run in parallel, and findings are merged.

The scan command supports a --merge flag:

scannet scan [email protected]:org/project.git --branch=main --merge=true

This runs both the current and the new models in parallel and combines their findings:

{
  "findings": [
    {
      "id": "fnd-1a2b3c",
      "sources": [
        { "model": "sast-2023-q2", "confidence": 0.78 },
        { "model": "sast-2023-q3", "confidence": 0.89 }
      ],
      "merged_severity": "high",
      "merged_confidence": 0.84
    }
  ]
}

The engine also supports --dry-run to preview changes without committing.

Common Pitfalls

  • Confusing threshold and confidence: A finding with confidence 0.85 may be marked high severity, but if the threshold is 0.75, a low-confidence result (0.6) is missed entirely. The engine logs:
  WARNING: Finding fnd-1a2b3c has confidence 0.62, below threshold 0.75. Consider lowering threshold.
  • Overlapping scans: If two scans run concurrently on the same branch, the engine logs:
  WARNING: Scan scn-7f9e3a2c is running concurrently with scn-7f9e3a2d. Using advisory locking.
  • Model drift: Over time, new data shifts feature distributions. The engine computes drift metrics and logs:
  DRIFT: Model sast-2023-q3 shows significant drift in feature distribution (KLD = 0.42). Recommend retraining.
  • Incomplete reports: When report command is called but no findings are available, it returns:
  {
    "scan_id": "scn-7f9e3a2c",
    "summary": "No findings recorded.",
    "findings": []
  }

The scanning system is resilient but expects careful attention to configuration, model versioning, and input validation. The only error that silently fails is a missing scannet binary in the CI runner path—this causes a scan to run without any output, but no logs or artifacts are produced.

This page was rewritten on 11 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.