Skip to content
Report library
Purpose / Development

Golang Modernize Skill Security Audit

What the author says it does (original text)

Modernize Golang code to use recent language features, standard library improvements, and idiomatic patterns. Use when reviewing Go code with old-style patterns, when encountering a deprecation warning, or when the user asks for modernization, a Go version upgrade (e.g. to Go 1.27), or a CI/tooling refresh. Not for structural refactors, extracting functions, or moving code between packages (→ See

Independent security check

Security risks found

Files checked
4
Risks found
6
Could it run dangerous commands?Looks for programs run straight after downloading, remote control of your computer, and hidden commands.Risks found: 1
Medium risk

The default test step executes repository code

Source references: 1
What we found

The workflow requires `go test ./...`, not just static source inspection. Go tests and package initialization code run on the user's machine, which goes beyond a read-only scan when the repository is untrusted or newly obtained.

Why this matters

Malicious or side-effecting test code could read environment variables and local files, start processes, or transmit data when network access is available.

This is an active workflow step, not an example: the Skill requires `go test ./...`. That compiles and executes repository tests, package initialization code, and programs invoked by tests. In an untrusted repository, this could access files, credentials, or the network with the user's permissions. The user can require static-only review or testing in a credential-free sandbox with restricted filesystem and network access.

SKILL.md:52In the instructionsOpen original file
4. **Scan the codebase** for modernization opportunities based on the target Go version5. **Run `golangci-lint`** with the `modernize` linter if available, and `go test ./...` — Go 1.27+ runs the `stdversion` vet check by default, flagging APIs newer than the module's `go` directive; bump the directive or revert the suggestion, don't ignore the hit6. **Suggest improvements contextually**:
Could it expose your files or keys?Looks for uploads of files containing passwords or keys, and keys written directly in the code.No risks found
Could it delete files or keep running?Looks for broad file deletion, disk overwrites, and programs set to start automatically.Risks found: 3
Medium risk

A full scan proceeds to a multi-file rewrite without a separate approval gate

Source references: 2
What we found

After the explicit scan, the instructions directly tell the agent to apply the repository-wide rewrite. An isolated worktree protects the main tree, but it does not establish approval for every migration or remove the risk of extensive changes.

Why this matters

Automated migrations can alter APIs, serialization, randomness, dependencies, or build behavior and create a large, difficult-to-review diff.

Full-scan mode calls the scan read-only but then directs the agent to apply the codebase-wide rewrite in an isolated worktree without explicit per-change approval. A worktree protects the main tree, but files are still created and broadly changed; it is unclear whether invocation alone authorizes automatic application. The user can require a report-only scan and approve specific migrations before any worktree or edits are created.

SKILL.md:32In the instructionsOpen original file
- **Inline mode** (developer is actively coding): suggest only modernizations relevant to the current file or feature. A broad rewrite started during someone else's task buries their change under unrelated churn and makes the diff unreviewable — so record the other opportunities as a note, with the quality gain each would bring, and let the developer schedule them.- **Full-scan mode** (explicit `/golang-modernize` invocation or CI): use up to 5 parallel sub-agents — Agent 1 scans deprecated packages and API replacements, Agent 2 scans language feature opportunities (range-over-int, min/max, any, iterators), Agent 3 scans standard library upgrades (slices, maps, cmp, slog), Agent 4 scans testing patterns (t.Context, b.Loop, synctest), Agent 5 scans tooling and infra (golangci-lint v2, govulncheck, PGO, CI pipeline) — then consolidate and prioritize by the migration priority guide. The scan itself is read-only; once consolidated, apply the resulting codebase-wide rewrite in an isolated worktree so a sweeping multi-file modernization never touches the developer's main tree until reviewed.
Show 1 other places
SKILL.md:56In the instructionsOpen original file
   - If invoked explicitly via `/golang-modernize` or in CI, scan and suggest across the entire codebase.7. **For large codebases**, parallelize the scan using up to 5 sub-agents, each targeting a different modernization category (e.g. deprecated packages, language features, standard library upgrades, testing patterns, tooling and infra). Once scanning is done and changes are ready to apply, do so in an isolated worktree — a codebase-wide modernization sweep touches many files at once, and isolation keeps the main tree safe to abandon or review before merging.8. **Before suggesting a dependency update**, run `go mod tidy` and the test suite to verify compatibility. Ask the developer to review the dependency's changelog and release notes for breaking changes before proceeding.
Medium risk

Merely preparing a dependency suggestion can modify module files

Source references: 1
What we found

The Skill requires `go mod tidy` before suggesting a dependency update. That command can rewrite `go.mod` and `go.sum`, remove apparently unused dependencies, and download modules, so the suggestion phase is not read-only.

Why this matters

The worktree may acquire unexpected dependency changes; projects with build tags, generated code, or incomplete environments can also have dependencies removed or resolved incorrectly.

The instruction explicitly requires `go mod tidy` and tests before merely suggesting a dependency update. `go mod tidy` is a write operation that can rearrange or remove `go.mod`/`go.sum` entries, while tests execute repository code. Thus a suggestion-stage action may change user files and run untrusted code. The user can require a proposal and diff preview first, with tidy and tests run only after approval in an isolated worktree.

SKILL.md:57In the instructionsOpen original file
7. **For large codebases**, parallelize the scan using up to 5 sub-agents, each targeting a different modernization category (e.g. deprecated packages, language features, standard library upgrades, testing patterns, tooling and infra). Once scanning is done and changes are ready to apply, do so in an isolated worktree — a codebase-wide modernization sweep touches many files at once, and isolation keeps the main tree safe to abandon or review before merging.8. **Before suggesting a dependency update**, run `go mod tidy` and the test suite to verify compatibility. Ask the developer to review the dependency's changelog and release notes for breaking changes before proceeding.9. **If the developer explicitly ignores a suggestion**, write a short memo to `.modernize` in the project root so it is not suggested again. Format: one line per ignored suggestion, with a short description.
Low risk

Declining a suggestion still creates a persistent project record

Source references: 2
What we found

When the user explicitly ignores a suggestion, the Skill writes it to `.modernize`. This turns a refusal into a repository change even if the user only intended to end the discussion and did not request documentation.

Why this matters

It can create an unexpected uncommitted file or place dated team decisions under version control, while also changing future scan results.

This is an explicit persistent-write instruction: after the user ignores a suggestion, the Skill writes `.modernize` in the project root. Although intended to prevent repeated prompts and limited to a short memo, ignoring advice does not necessarily authorize a repository change; it may create an unexpected dirty worktree or committed record. The user can require session-only memory or separate confirmation before writing.

SKILL.md:58In the instructionsOpen original file
8. **Before suggesting a dependency update**, run `go mod tidy` and the test suite to verify compatibility. Ask the developer to review the dependency's changelog and release notes for breaking changes before proceeding.9. **If the developer explicitly ignores a suggestion**, write a short memo to `.modernize` in the project root so it is not suggested again. Format: one line per ignored suggestion, with a short description.
Show 1 other places
SKILL.md:62In the instructionsOpen original file
### `.modernize` file format```# Ignored modernization suggestions# Format: <date> <category> <description>2026-01-15 slog-migration Team decided to keep zap for now2026-02-01 math-rand-v2 Legacy module requires math/rand compatibility```
Could it bypass safety checks?Looks for skipped website security checks, excessive file access, or actions that skip your approval.Risks found: 1
Low risk

The permission set includes every git subcommand and external web tools

Source references: 2
What we found

The declaration allows `Bash(git:*)` together with file writes, WebFetch, WebSearch, and sub-agents. The described modernization workflow only clearly needs inspection, an isolated worktree, and controlled edits; the git wildcard also covers pushes, branch deletion, and destructive history operations.

Why this matters

If instructions are misinterpreted, influenced by repository content, or executed incorrectly, local Git state or a remote repository could be affected. Web tools also enlarge the possible path for source or metadata disclosure. Permission alone does not prove these actions occur.

What this evidence establishes

The declaration permits broadly matched git commands, file writes, web retrieval, and agents, but capability alone does not show that the Skill will push, delete branches, or rewrite history. The visible workflow only calls for an isolated worktree and emphasizes review or abandonment; no push/reset/delete instruction is shown. Risk depends on how the host enforces `allowed-tools`. The user can restrict git to read-only/worktree operations and disable unnecessary network or write access.

This assessment concerns the code and conditions shown, not proof that harm has occurred.
SKILL.md:18In the instructionsOpen original file
    skill-library-version: "1.27"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch WebSearch AskUserQuestion EnterWorktree ExitWorktreepaths:
Show 1 other places
SKILL.md:56In the instructionsOpen original file
   - If invoked explicitly via `/golang-modernize` or in CI, scan and suggest across the entire codebase.7. **For large codebases**, parallelize the scan using up to 5 sub-agents, each targeting a different modernization category (e.g. deprecated packages, language features, standard library upgrades, testing patterns, tooling and infra). Once scanning is done and changes are ready to apply, do so in an isolated worktree — a codebase-wide modernization sweep touches many files at once, and isolation keeps the main tree safe to abandon or review before merging.8. **Before suggesting a dependency update**, run `go mod tidy` and the test suite to verify compatibility. Ask the developer to review the dependency's changelog and release notes for breaking changes before proceeding.
Could it mislead the AI or hide text?Checks the skill instructions for requests to ignore you, influence the report, or hide text in invisible characters.Risks found: 1
Low risk

The Skill tells the agent to persuade users about unrelated improvements

Source references: 3
What we found

A live instruction says to “TRY TO CONVINCE” the user even while forbidding direct unrelated large refactors. This can turn optional maintenance advice into pressure rather than a neutral tradeoff. The later rule to ask once and honor a skip mitigates the risk.

Why this matters

A user may approve work beyond the current task after repeated emphasis on quality benefits, increasing review burden and change scope.

Legitimate use of this code

“TRY TO CONVINCE” is persuasive wording, but the same context forbids large unrelated refactoring. More specific mode rules require asking only once, permit skipping, and require immediate silence for the rest of the session after a skip; inline mode also limits suggestions to current work and records other opportunities only as notes. The visible behavior is therefore solicitation of optional advice, not bypassing the user's decision or forcing changes. The user can simply choose to skip.

This assessment concerns the code and conditions shown, not proof that harm has occurred.
SKILL.md:42In the instructionsOpen original file
You MUST NEVER conduct large refactoring if the developer is working on a different task. But TRY TO CONVINCE your human it would improve the code quality.
Show 2 other places
SKILL.md:34In the instructionsOpen original file
**Questions:** In Inline mode, this skill triggers contextually while the developer is working on something else — ask via the environment's question tool, once, whether to suggest the modernization opportunities noticed or skip for now. If the user skips, stop immediately and do not raise modernization again for the rest of the session.
SKILL.md:31In the instructionsOpen original file
- **Inline mode** (developer is actively coding): suggest only modernizations relevant to the current file or feature. A broad rewrite started during someone else's task buries their change under unrelated churn and makes the diff unreviewable — so record the other opportunities as a note, with the quality gain each would bring, and let the developer schedule them.- **Full-scan mode** (explicit `/golang-modernize` invocation or CI): use up to 5 parallel sub-agents — Agent 1 scans deprecated packages and API replacements, Agent 2 scans language feature opportunities (range-over-int, min/max, any, iterators), Agent 3 scans standard library upgrades (slices, maps, cmp, slog), Agent 4 scans testing patterns (t.Context, b.Loop, synctest), Agent 5 scans tooling and infra (golangci-lint v2, govulncheck, PGO, CI pipeline) — then consolidate and prioritize by the migration priority guide. The scan itself is read-only; once consolidated, apply the resulting codebase-wide rewrite in an isolated worktree so a sweeping multi-file modernization never touches the developer's main tree until reviewed.
Could it change links or payment recipients without asking?Looks for forced referral or payment changes combined with instructions to hide the change.No risks found

Inside this skill

8 instruction sections

This Skill modernizes Go projects by reading the project Go version and `.modernize` records, scanning source code, and running linting and the full test suite.

View source
SKILL.md:48In the instructionsOpen original file
1. **Check the project's `go.mod` or `go.work`** to determine the current Go version (`go` directive)2. **Check the latest Go version** using the Go Version Changelogs table below and suggest upgrading if the project's `go.mod` is behind3. **Read `.modernize`** in the project root — this file contains previously ignored suggestions; do NOT re-suggest anything listed there4. **Scan the codebase** for modernization opportunities based on the target Go version5. **Run `golangci-lint`** with the `modernize` linter if available, and `go test ./...` — Go 1.27+ runs the `stdversion` vet check by default, flagging APIs newer than the module's `go` directive; bump the directive or revert the suggestion, don't ignore the hit6. **Suggest improvements contextually**:

An explicit full-codebase scan examines five categories in parallel. The scan is described as read-only, but the Skill then directs the agent to apply the consolidated repository-wide rewrite in an isolated worktree.

View source
SKILL.md:32In the instructionsOpen original file
- **Inline mode** (developer is actively coding): suggest only modernizations relevant to the current file or feature. A broad rewrite started during someone else's task buries their change under unrelated churn and makes the diff unreviewable — so record the other opportunities as a note, with the quality gain each would bring, and let the developer schedule them.- **Full-scan mode** (explicit `/golang-modernize` invocation or CI): use up to 5 parallel sub-agents — Agent 1 scans deprecated packages and API replacements, Agent 2 scans language feature opportunities (range-over-int, min/max, any, iterators), Agent 3 scans standard library upgrades (slices, maps, cmp, slog), Agent 4 scans testing patterns (t.Context, b.Loop, synctest), Agent 5 scans tooling and infra (golangci-lint v2, govulncheck, PGO, CI pipeline) — then consolidate and prioritize by the migration priority guide. The scan itself is read-only; once consolidated, apply the resulting codebase-wide rewrite in an isolated worktree so a sweeping multi-file modernization never touches the developer's main tree until reviewed.

The metadata defines no installation steps, but grants read/write access, Go and golangci-lint commands, all git subcommands, web access, and sub-agent capabilities.

View source
SKILL.md:13In the instructionsOpen original file
    homepage: https://github.com/samber/cc-skills-golang    requires:      bins:        - go    install: []    skill-library-version: "1.27"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch WebSearch AskUserQuestion EnterWorktree ExitWorktreepaths:

The tooling guide recommends upgrading the toolchain, adding latest-version tool dependencies, and running automated source transformations; these commands can modify source or module files rather than merely produce recommendations.

View source
references/tooling.md:13In the instructionsOpen original file
# Update go.mod to target a newer versiongo mod edit -go=1.27# Update toolchaingo get toolchain@latest```
references/tooling.md:30In the instructionsOpen original file
```bash# Pin in the module (Go 1.24+)go get -tool golang.org/x/vuln/cmd/govulncheck@latest# Scan source codego tool govulncheck ./...
references/tooling.md:64In the instructionsOpen original file
```bashgo fix ./...          # applies the enabled safe transformationsgo tool fix help      # check exact fixer coverage for the installed toolchain```
Start here · InstructionsSKILL.md
golang-modernize
Lines connect the instruction file to its sections, not an observed execution order. Select a section to read the source. 1 more sections are available in the original file.

File reference map

References: 3
Files making referencesReferenced content
Lines show actual file references, not execution order. Select a node to highlight its connections and inspect the files and source locations. Dashed lines include files that still need locating.
Files and check records4 files

Coverage and gaps

Content covered in each file

These are the source ranges included in this check, not a guarantee that every issue has been resolved.

  • SKILL.mdFull text included
  • references/tooling.mdFull text included
  • references/versions.mdFull text included
  • evals/evals.jsonFull text included

This report is for the version above. We read the available code and instructions without running the skill or checking extra packages it installs. This is not a promise of safety: a different version or setup may behave differently.

  • SKILL.mdInstructions
  • evals/evals.jsonSupporting file
  • references/tooling.mdSupporting file
  • references/versions.mdSupporting file

Operations mentioned in code and instructions

Connect to websites
SKILL.md:12In the instructionsOpen original file
    emoji: "🔄"    homepage: https://github.com/samber/cc-skills-golang    requires:
SKILL.md:77In the instructionsOpen original file
| ------- | ------------- | --------------------------- || Go 1.21 | August 2023   | <https://go.dev/doc/go1.21> || Go 1.22 | February 2024 | <https://go.dev/doc/go1.22> |
SKILL.md:78In the instructionsOpen original file
| Go 1.21 | August 2023   | <https://go.dev/doc/go1.21> || Go 1.22 | February 2024 | <https://go.dev/doc/go1.22> || Go 1.23 | August 2024   | <https://go.dev/doc/go1.23> |
Run commands
SKILL.md:18In the instructionsOpen original file
    skill-library-version: "1.27"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch WebSearch AskUserQuestion EnterWorktree ExitWorktreepaths:
references/tooling.md:9In the instructionsOpen original file
```bash# Check current version
references/tooling.md:30In the instructionsOpen original file
```bash# Pin in the module (Go 1.24+)
Read files
evals/evals.json:36In the instructionsOpen original file
      "name": "safety-over-cosmetic",      "prompt": "Modernize this Go 1.24 HTTP file server code. Suggest all improvements.\n\n```go\npackage fileserver\n\nimport (\n    \"fmt\"\n    \"io\"\n    \"net/http\"\n    \"os\"\n    \"path/filepath\"\n)\n\ntype FileServer struct {\n    baseDir string\n}\n\nfunc NewFileServer(baseDir string) *FileServer {\n    return &FileServer{baseDir: baseDir}\n}\n\nfunc (fs *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n    userPath := r.URL.Query().Get(\"path\")\n    if userPath == \"\" {\n        http.Error(w, \"missing path parameter\", http.StatusBadRequest)\n        return\n    }\n\n    fullPath := filepath.Join(fs.baseDir, filepath.Clean(userPath))\n\n    f, err := os.Open(fullPath)\n    if err != nil {\n        http.Error(w, \"file not found\", http.StatusNotFound)\n        return\n    }\n    defer f.Close()\n\n    w.Header().Set(\"Content-Type\", \"application/octet-stream\")\n    io.Copy(w, f)\n}\n\nfunc process(data interface{}) interface{} {\n    return data\n}\n\nfunc minVal(a, b int) int {\n    if a < b { return a }\n    return b\n}\n\nfunc formatAddr(host string, port int) string {\n    return fmt.Sprintf(\"%s:%d\", host, port)\n}\n```\n\nThe project targ       "trap": "The code has a path traversal vulnerability (filepath.Join + filepath.Clean is insufficient). Without the skill, the model may prioritize cosmetic changes (interface{}->any, min builtin) over the security-critical os.Root fix 
evals/evals.json:104In the instructionsOpen original file
      "name": "addcleanup-vs-setfinalizer",      "prompt": "Review this resource management code for Go 1.24 best practices.\n\n```go\npackage pool\n\nimport (\n    \"database/sql\"\n    \"fmt\"\n    \"runtime\"\n)\n\ntype ManagedConn struct {\n    db   *sql.DB\n    name string\n    dsn  string\n}\n\nfunc NewManagedConn(dsn, name string) (*ManagedConn, error) {\n    db, err := sql.Open(\"postgres\", dsn)\n    if err != nil {\n        return nil, fmt.Errorf(\"opening db: %w\", err)\n    }\n    mc := &ManagedConn{db: db, name: name, dsn: dsn}\n    runtime.SetFinalizer(mc, func(c *ManagedConn) {\n        c.db.Close()\n    })\n    return mc, nil\n}\n\ntype TempFile struct {\n    path string\n    fd   int\n}\n\nfunc NewTempFile(path string, fd int) *TempFile {\n    tf := &TempFile{path: path, fd: fd}\n    runtime.SetFinalizer(tf, func(f *TempFile) {\n        syscallClose(f.fd)\n        osRemove(f.path)\n    })\n    return tf\n}\n\nfunc syscallClose(fd int) {}\nfunc osRemove(path string) {}\n```\n\nModernize the cleanup pattern. Explain why the current approach has problems.",      "trap": "New Go code should consider runtime.AddCleanup instead of runtime.SetFinalizer because it is less error-prone. The key API difference: AddCleanup takes the resource as a separate argument (not the whole object). Without the s 
references/versions.md:423In the instructionsOpen original file
path := filepath.Join(baseDir, userInput)data, err := os.ReadFile(path)
Read keys or account settings
evals/evals.json:90In the instructionsOpen original file
      "name": "cmp-or-chained-defaults",      "prompt": "Clean up this configuration loading code. We're on Go 1.22. The nested if/else chains for default values are hard to read.\n\n```go\npackage config\n\nimport \"os\"\n\ntype Config struct {\n    Host     string\n    Port     string\n    LogLevel string\n    Region   string\n    Mode     string\n}\n\nfunc LoadConfig() Config {\n    host := os.Getenv(\"HOST\")\n    if host == \"\" {\n        host = os.Getenv(\"HOSTNAME\")\n    }\n    if host == \"\" {\n        host = os.Getenv(\"SERVICE_HOST\")\n    }\n    if host == \"\" {\n        host = \"localhost\"\n    }\n\n    port := os.Getenv(\"PORT\")\n    if port == \"\" {\n        port = os.Getenv(\"HTTP_PORT\")\n    }\n    if port == \"\" {\n        port = \"8080\"\n    }\n\n    logLevel := os.Getenv(\"LOG_LEVEL\")\n    if logLevel == \"\" {\n        logLevel = os.Getenv(\"LOGLEVEL\")\n    }\n    if logLevel == \"\" {\n        logLevel = \"info\"\n    }\n\n    region := os.Getenv(\"AWS_REGION\")\n    if region == \"\" {\n        region = os.Getenv(\"REGION\")\n    }\n    if region == \"\" {\n        region = \"us-east-1\"\n    }\n\n    mode := os.Getenv(\"APP_MODE\")\n    if mode == \"\" {\n        mode = \"production\"\n       "trap": "Go 1.22 introduced cmp.Or(a, b, c...) which returns the first non-zero value. It collapses multi-step default chains to single lines. Without the skill, the model will likely keep the if/else chains or use a custom helper fun 
references/versions.md:175In the instructionsOpen original file
// Beforeaddr := os.Getenv("ADDR")if addr == "" { addr = ":8080" }
references/versions.md:179In the instructionsOpen original file
// After (Go 1.22+)addr := cmp.Or(os.Getenv("ADDR"), ":8080")```
Change files
evals/evals.json:303In the instructionsOpen original file
      "name": "go127-synctest-http",      "prompt": "This Go 1.27 HTTP handler test is flaky in CI because of real timeouts. Make it deterministic and fast.\n\n```go\npackage api\n\nimport (\n    \"io\"\n    \"net/http\"\n    \"net/http/httptest\"\n    \"testing\"\n    \"time\"\n)\n\nfunc Handler(w http.ResponseWriter, r *http.Request) {\n    time.Sleep(100 * time.Millisecond) // simulates slow backend\n    w.Write([]byte(\"ok\"))\n}\n\nfunc TestHandlerResponds(t *testing.T) {\n    srv := httptest.NewServer(http.HandlerFunc(Handler))\n    defer srv.Close()\n\n    client := &http.Client{Timeout: 5 * time.Second}\n    resp, err := client.Get(srv.URL)\n    if err != nil {\n        t.Fatal(err)\n    }\n    defer resp.Body.Close()\n    body, _ := io.ReadAll(resp.Body)\n    if string(body) != \"ok\" {\n        t.Fatalf(\"got %q\", body)\n    }\n}\n\nfunc TestHandlerClientTimeout(t *testing.T) {\n    srv := httptest.NewServer(http.HandlerFunc(Handler))\n    defer srv.Close()\n\n    client := &http.Client{Timeout: 50 * time.Millisecond} // shorter than handler sleep\n    _, err := client.Get(srv.URL)\n    if err == nil {\n        t.Fatal(\"expected timeout error\")\n    }\n}\n```\n\nProvide the fixed tests. Do not just incre       "trap": "testing/synctest makes time-based tests deterministic, but a plain httptest.NewServer uses the real network, which stalls inside a synctest bubble (the bubble's fake clock waits forever on real I/O). Go 1.27 added httptest.Ne 
Lines read
1,548
File checksum (to compare versions)
595699934fd3a33bd2afc08a2590a401b681f51845aee991a943a44aa6a735f7