Skip to content

p/docker-compose rules fail when obsolete version attribute is omitted #4035

Description

@webpwnized

Describe the bug

The Semgrep Community Docker Compose rules appear to depend on the obsolete top-level Docker Compose version attribute.

When version is omitted from a valid modern Docker Compose file, at least the following rules fail to report findings:

yaml.docker-compose.security.no-new-privileges.no-new-privileges

yaml.docker-compose.security.writable-filesystem-service.writable-filesystem-service

When the same Compose file is given:

version: '3.8'

both findings are reported as expected.

Modern Docker Compose treats the top-level version attribute as obsolete and ignores it, so valid Compose files without version should still be analyzed correctly.

To Reproduce

Use this Docker Compose file without a top-level version attribute:

services:
  www:
    container_name: www
    image: docker.io/webpwnized/dragonfly:www

    ports:
      - 127.0.0.1:80:80
      - 127.0.0.1:8888:80

    networks:
      - httpnet

networks:
  httpnet:

This service intentionally omits both:

security_opt:
  - no-new-privileges:true

and:

read_only: true

Run the Docker Compose Community ruleset:

docker run --rm \
  -v "$(pwd)/.build:/mnt/src:ro" \
  docker.io/semgrep/semgrep:latest \
  semgrep scan \
    --config p/docker-compose \
    /mnt/src \
    --error

Semgrep reports no findings for the missing no-new-privileges and writable root filesystem conditions.

The individual no-new-privileges rule also fails:

docker run --rm \
  -v "$(pwd)/.build:/mnt/src:ro" \
  docker.io/semgrep/semgrep:latest \
  semgrep scan \
    --config r/yaml.docker-compose.security.no-new-privileges.no-new-privileges \
    /mnt/src \
    --error

Result:

Findings: 0
Rules run: 1
Targets scanned: 1
Parsed lines: ~100.0%

Now add only this line at the top of the same file:

version: '3.8'

The file becomes:

version: '3.8'

services:
  www:
    container_name: www
    image: docker.io/webpwnized/dragonfly:www

    ports:
      - 127.0.0.1:80:80
      - 127.0.0.1:8888:80

    networks:
      - httpnet

networks:
  httpnet:

Run the same Semgrep scans again.

The missing no-new-privileges rule now fires:

yaml.docker-compose.security.no-new-privileges.no-new-privileges

Service 'www' allows for privilege escalation via setuid or setgid binaries.
Add 'no-new-privileges:true' in 'security_opt' to prevent this.

The writable root filesystem rule also fires:

yaml.docker-compose.security.writable-filesystem-service.writable-filesystem-service

Service 'www' is running with a writable root filesystem. This may allow malicious applications to
download and run additional payloads, or modify container files. If an application inside a
container has to save something temporarily consider using a tmpfs. Add 'read_only: true' to this
service to prevent this.

The only relevant change is the addition of:

version: '3.8'

Expected behavior

These Docker Compose security rules should detect the vulnerable service configuration regardless of whether the obsolete top-level version attribute is present.

Both of these should be equivalent scan targets:

version: '3.8'

services:
  www:
    image: docker.io/webpwnized/dragonfly:www

and:

services:
  www:
    image: docker.io/webpwnized/dragonfly:www

The second form is valid modern Docker Compose syntax and should not cause these security rules to stop matching.

Screenshots

I can provide screenshots of both scan results if useful.

What is the priority of the bug to you?

  • P0: blocking your adoption of Semgrep or workflow
  • P1: important to fix or quite annoying
  • P2: regular bug that should get fixed

Environment

Semgrep is being run using the official Docker image:

docker.io/semgrep/semgrep:latest

The source is mounted read-only into the scanner container:

-v "$(pwd)/.build:/mnt/src:ro"

The affected rules are:

yaml.docker-compose.security.no-new-privileges.no-new-privileges

yaml.docker-compose.security.writable-filesystem-service.writable-filesystem-service

The rules are exercised through:

p/docker-compose

and, for isolated testing:

r/yaml.docker-compose.security.no-new-privileges.no-new-privileges

Semgrep version can be obtained with:

docker run --rm docker.io/semgrep/semgrep:latest semgrep --version

Use case

I am evaluating Semgrep Community Edition for a large-scale GitOps-based SAST architecture where Docker Compose and application security rules would run automatically in CI/CD pipelines.

The intent is to run broad Community rulesets in audit mode and promote selected high-confidence rules into blocking controls.

A structural dependency on the obsolete Docker Compose version attribute creates a significant false-negative risk because modern Compose files commonly omit that field. Fixing these rules would allow the same security controls to work correctly against current Docker Compose syntax without requiring organizations to retain an obsolete configuration attribute solely for SAST compatibility.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions