How to Use Experimental Exclude Patterns in osv-scanner Scans

Use the --experimental-exclude flag with osv-scanner scan source to skip directories using exact matches, glob patterns (prefix with g:), or regular expressions (prefix with r:).

The osv-scanner tool from Google provides an experimental mechanism to filter directories during vulnerability scans. This feature parses exclusion rules from the command line, compiles them into optimized matchers, and injects them into the underlying Scalibr scanning engine. Understanding how these experimental exclude patterns are processed helps you optimize scan times by eliminating irrelevant paths like test suites or dependency caches.

How the Experimental Exclude Flag Works

The implementation spans multiple packages, converting CLI arguments into compiled patterns that the file system walker uses to prune directories.

CLI Flag Definition

The flag is declared in cmd/osv-scanner/scan/source/command.go as a StringSliceFlag, allowing multiple exclusion rules in a single scan:

&cli.StringSliceFlag{
    Name:  "experimental-exclude",
    Usage: "exclude directory paths during scanning; use g:pattern for glob, r:pattern for regex, or just dirname for exact match (can be repeated)",
},

The parsed values are stored in experimentalScannerActions.ExcludePatterns before being passed to the scanning logic.

Pattern Parsing and Compilation

In pkg/osvscanner/exclude.go, the parseExcludePatterns function processes each argument. It uses parseExcludeArg to split entries into a type prefix and raw pattern:

  • Exact match – no prefix (stored in dirsToSkip)
  • Globg: prefix (compiled using github.com/gobwas/glob)
  • Regexr: prefix (compiled into a cached regexp.Regexp)

The compiled results are held in the excludePatterns struct:

type excludePatterns struct {
    dirsToSkip   []string
    globPattern  glob.Glob
    regexPattern *regexp.Regexp
}

Glob patterns are merged internally with {p1,p2,…} syntax, while regex patterns use alternation (p1|p2|…) for efficiency.

Scanner Integration

The DoScan function in pkg/osvscanner/scan.go injects these patterns into the Scalibr configuration:

DirsToSkip:   excludePatterns.dirsToSkip,
SkipDirRegex: excludePatterns.regexPattern,
SkipDirGlob:  excludePatterns.globPattern,

Scalibr’s directory walker checks each path against these three matchers during the file system traversal. Any match causes the walker to skip that directory and its children silently.

Pattern Syntax and Types

osv-scanner supports three distinct pattern types, differentiated by their prefix.

Exact Directory Names

Provide the directory name without any prefix to exclude specific folder names regardless of their location in the tree. These are collected in the dirsToSkip slice and matched literally against path components.

osv-scanner scan source -r \
    --experimental-exclude=test \
    --experimental-exclude=docs \
    ./my/project

Glob Patterns

Prefix the pattern with g: to use glob syntax. This supports wildcards like * (single level) and ** (recursive) to match directories at any depth.

osv-scanner scan source -r \
    --experimental-exclude="g:**/vendor/**" \
    ./my/project

The glob compiler merges multiple patterns for efficient matching.

Regular Expressions

Prefix with r: to supply a RE2-compatible regular expression. This is useful for complex exclusion rules, such as matching directories ending with specific suffixes.

osv-scanner scan source -r \
    --experimental-exclude="r:\\.cache$" \
    ./my/project

Malformed regex patterns return an error during the compilation phase.

Command Line Examples

You can combine multiple pattern types in a single scan by repeating the flag:


# Mixed exclusion: exact name, glob, and regex

osv-scanner scan source -r \
    --experimental-exclude=nested \
    --experimental-exclude="g:**/test/**" \
    --experimental-exclude="r:^tmp_" \
    ./my/project

All exclusions are documented in docs/scan-source.md along with usage notes.

Programmatic Usage

When integrating osv-scanner into Go applications, populate the ExperimentalScannerActions struct:

package main

import (
    "github.com/google/osv-scanner/v2/pkg/osvscanner"
    "github.com/google/osv-scanner/v2/internal/helper"
)

func main() {
    exp := osvscanner.ExperimentalScannerActions{
        ExcludePatterns: []string{
            "vendor",                 // exact match
            "g:**/test/**",           // glob
            "r:\\.cache$",            // regex
        },
    }

    scan := helper.CommonScannerActions{
        Recursive: true,
        DirectoryPaths: []string{"./my/project"},
        ExperimentalScannerActions: exp,
    }

    results, err := osvscanner.DoScan(scan)
    if err != nil && err != osvscanner.ErrNoPackagesFound {
        panic(err)
    }
    // Process results...
}

The ExcludePatterns slice flows through the same parsing pipeline used by the CLI, as defined in pkg/osvscanner/exclude.go.

Summary

Frequently Asked Questions

Is the exclude pattern feature stable?

No, this is an experimental feature. The --experimental-exclude flag name, syntax, and behavior may change in future releases of osv-scanner as the implementation matures. Monitor the project’s changelog for updates.

Can I use multiple exclude patterns in one command?

Yes. The flag accepts multiple values. You can repeat --experimental-exclude with different patterns, mixing exact names, globs, and regexes in the same scan invocation. The scanner applies all patterns cumulatively.

What regex engine does osv-scanner use?

The tool uses Go’s standard regexp package (RE2 syntax) for regex patterns. Patterns prefixed with r: must be valid RE2 expressions; otherwise, parseExcludePatterns returns a compilation error before scanning begins.

How do I exclude directories nested at any depth?

Use a glob pattern with the ** wildcard. Prefix your pattern with g: and use syntax like **/vendor/** to match and exclude vendor directories regardless of their depth in the project hierarchy.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →