Skip to content

bug(container): image/tag parsing fails for registries with port numbers #1139

@suzutan

Description

@suzutan

Describe the bug

Container image parsing is broken when the registry URL has a port number. The code splits on ALL colons with strings.Split(image, ":"), so it can't tell the difference between a registry port and an image tag.

This is the same bug as #825, which got auto-closed by the stale bot without being fixed.

How to reproduce it

  1. Run a container with an image from a registry that has a port:

    docker run registry.example.com:5000/foo/bar:latest
  2. Check Falco output for container.image.repository and container.image.tag fields

  3. The values will be incorrect:

    • For registry.example.com:5000/foo/bar:latest:
      • Splits into 3 parts, fails len == 2 check, leaves repo and tag empty
    • For registry.example.com:5000/foo/bar:
      • container.image.repository = "registry.example.com" (wrong - missing port and path)
      • container.image.tag = "5000/foo/bar" (wrong - port and path parsed as tag)

Expected behaviour

For registry.example.com:5000/foo/bar:latest:

  • container.image.repository = "registry.example.com:5000/foo/bar"
  • container.image.tag = "latest"

For registry.example.com:5000/foo/bar:

  • container.image.repository = "registry.example.com:5000/foo/bar"
  • container.image.tag = "" or "latest"

Screenshots

N/A

Environment

  • Falco version: 0.42.1(plugins/container 0.4.1)
  • System info: Ubuntu 22.04.5 LTS / containerd://2.1.5
  • Cloud provider or hardware configuration:
  • OS: Ubuntu
  • Kernel: 5.15.0-157-generic
  • Installation method: kubernetes with Falco helm chart

Additional context

Affected code locations:

The bug exists in 4 files in the plugins repository:

  1. plugins/container/go-worker/pkg/container/podman.go:109-112
  2. plugins/container/go-worker/pkg/container/containerd.go:150-153
  3. plugins/container/go-worker/pkg/container/cri.go:325-328
  4. plugins/container/go-worker/pkg/container/docker.go:203-213

All using the same broken pattern:

imageRepoTag := strings.Split(image, ":")
if len(imageRepoTag) == 2 {
    imageRepo = imageRepoTag[0]
    imageTag = imageRepoTag[1]
}

Verified in latest code:

Static analysis confirms this bug still exists in the latest main branch of the plugins repository (as of 2025-12-18, commit 419e315).

Impact:

This breaks for anyone using:

  • Private registries with ports (registry.company.com:5000/...)
  • Corporate registry setups
  • Digest-based images

Wrong image/tag data can break security policies, audit logs, and allowlists.

Proposed fix:

Split on the LAST colon, not all colons:

func splitImageAndTag(image string) (repo, tag string) {
    // Strip digest if present
    if idx := strings.Index(image, "@"); idx > 0 {
        image = image[:idx]
    }

    lastSlash := strings.LastIndex(image, "/")
    colonIdx := strings.LastIndex(image, ":")

    // Colon after last slash = tag separator
    if colonIdx > 0 && colonIdx > lastSlash {
        return image[:colonIdx], image[colonIdx+1:]
    }

    return image, ""
}

Or use an existing image reference parser like github.com/distribution/reference.

Test cases that should pass:

  • registry.example.com:5000/foo/bar:latest → repo: registry.example.com:5000/foo/bar, tag: latest
  • registry.example.com:5000/foo/bar → repo: registry.example.com:5000/foo/bar, tag: ""
  • docker.io/library/alpine:3.20.3 → repo: docker.io/library/alpine, tag: 3.20.3
  • alpine:3.20.3 → repo: alpine, tag: 3.20.3
  • alpine → repo: alpine, tag: ""

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions