Skip to content
Report library
Purpose / Other

Golang Spf13 Viper Skill Security Audit

What the author says it does (original text)

Golang configuration library using spf13/viper — layered precedence (flag > env > file > KV > default), BindPFlag/BindPFlags, SetEnvPrefix + SetEnvKeyReplacer + AutomaticEnv, ReadInConfig + ConfigFileNotFoundError, Unmarshal + mapstructure struct tags, Sub for sub-trees, WatchConfig + OnConfigChange for hot reload, viper.New() for test isolation, and remote KV integration. Apply when using or adop

Independent security check

Security risks found

Files checked
7
Risks found
4
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 installation command selects an unpinned `@latest` dependency

Source references: 1
What we found

The Skill directly recommends `go get github.com/spf13/viper@latest`. This accesses the network, downloads the newest available dependency code, and normally updates `go.mod` and `go.sum`; running it at different times can select different code.

Why this matters

An unreviewed release or transitive dependency could change build behavior, introduce compatibility problems, or increase supply-chain exposure, while leaving persistent dependency-file changes.

This is an installation recommendation in the live instructions and explicitly uses the floating `@latest` version. The version obtained therefore depends on when it is run, and the Go tool will contact dependency sources and update project dependency records. Installing Viper is consistent with the Skill's purpose, but this form is not reproducibly pinned. Users can request a tested exact version and review `go.mod`/`go.sum` changes. The source does not show automatic execution.

SKILL.md:40In the instructionsOpen original file
```bashgo get github.com/spf13/viper@latest```
Could it expose your files or keys?Looks for uploads of files containing passwords or keys, and keys written directly in the code.Risks found: 1
Medium risk

The debugging advice can print the entire resolved configuration, including credentials

Source references: 2
What we found

The Skill recommends printing `viper.AllSettings()` to verify bindings. That call returns all resolved settings, while the same guidance allows credential-related variables such as `GOOGLE_APPLICATION_CREDENTIALS` to be bound. Tokens, passwords, or connection strings could therefore be printed as well.

Why this matters

Sensitive configuration could persist in terminal history, CI logs, or centralized logging and become visible to anyone with log access.

This is a debugging example and does not run automatically. However, if followed, `AllSettings()` prints the complete resolved configuration to the terminal or logs. The Skill also demonstrates binding a credential-related environment variable into Viper, so passwords, tokens, or connection strings in a real project could be exposed with the rest of the settings. Users can ask for key-specific output or redaction.

references/binding-and-env.md:102In the instructionsOpen original file
Print all resolved values to verify your binding is correct:```gofmt.Println(viper.AllSettings())// map[database:map[host:localhost max_conn:25] port:8080]```
Show 1 other places
references/binding-and-env.md:32In the instructionsOpen original file
Use `AutomaticEnv` for the common case. Use `BindEnv` when you need to bind to an env var with a name that doesn't follow your prefix/replacer convention (e.g., third-party env vars like `GOOGLE_APPLICATION_CREDENTIALS`).```go// Bind a specific non-prefixed env varviper.BindEnv("google.credentials", "GOOGLE_APPLICATION_CREDENTIALS")```
Could it delete files or keep running?Looks for broad file deletion, disk overwrites, and programs set to start automatically.No risks found
Could it bypass safety checks?Looks for skipped website security checks, excessive file access, or actions that skip your approval.Risks found: 2
Medium risk

The declared tool permissions are broader than needed for Viper guidance

Source references: 1
What we found

The Skill requests file writing, unrestricted `go:*` and `git:*` commands, agent spawning, and web retrieval. In particular, `git:*` is not limited to read-only operations. If the host enforces this field as authorization, the Skill could alter repository state or contact remotes even though its prose does not request that behavior.

Why this matters

If the agent makes a mistake or is influenced by repository content, these broad permissions increase the possible scope of source changes, dependency execution, Git changes, or outbound data transfer. The evidence shows requested capability, not that such actions occurred.

What this evidence establishes

The metadata declares file writes, unrestricted `git:*`, Agent use, and network retrieval. If a host treats this field as authorization, those capabilities could affect a repository or access the network. However, the supplied source shows no Git command, Agent invocation, or automatic network workflow, and adopting Viper in a Go project can legitimately require edits and Go tooling. The permission list alone is insufficient to establish dangerous behavior; users can restrict tools to those needed for the specific task.

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.21.0"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*paths:  - "**/*.go"---
Medium risk

The remote-configuration example uses plaintext HTTP without authentication or integrity controls

Source references: 2
What we found

The etcd example connects to `http://127.0.0.1:2379` and immediately reads remote configuration. If this pattern is copied to a non-local or untrusted network, configuration traffic may lack encryption and server authentication.

Why this matters

A party able to observe or interfere with the network path could read configuration or tamper with service behavior. If configuration contains credentials, sensitive data could also be exposed.

Legitimate use of this code

The example uses unencrypted HTTP, but its target is specifically the loopback address `127.0.0.1`; the Consul example likewise uses `localhost`. The visible source does not instruct users to transmit configuration over a non-local or untrusted network. It also describes remote configuration as opt-in and warns about its network and runtime dependency. TLS, authentication, and access control would need review if a user substitutes a remote address, but that is not the behavior shown here.

This assessment concerns the code and conditions shown, not proof that harm has occurred.
references/sources-and-formats.md:84In the instructionsOpen original file
Viper supports remote KV stores via the `viper/remote` sub-package. This keeps remote config behind an opt-in import:```goimport _ "github.com/spf13/viper/remote"// etcdviper.AddRemoteProvider("etcd3", "http://127.0.0.1:2379", "/config/myapp.yaml")viper.SetConfigType("yaml")viper.ReadRemoteConfig()// Consulviper.AddRemoteProvider("consul", "localhost:8500", "myapp/config")viper.SetConfigType("json")viper.ReadRemoteConfig()```
Show 1 other places
references/sources-and-formats.md:100In the instructionsOpen original file
**Caution:** Remote config adds network latency to startup and a runtime dependency. Use it only when you need centralized config across many service instances. For most applications, files + env vars are sufficient.
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.No risks found
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 is an instructional Skill for using Viper in Go projects with configuration files, environment variables, flags, and remote KV stores. The supplied material contains no automatically executed scripts, and its install list is empty.

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.21.0"
SKILL.md:25In the instructionsOpen original file
# Using spf13/viper for layered configuration in GoViper resolves configuration values from multiple sources in a fixed precedence order. It has no user-facing surface — it doesn't define commands or flags. Its job is to answer "what is the value of key X right now?" by walking its source layers from highest to lowest priority.

The Skill describes merging configuration sources with a fixed precedence, where explicit settings, flags, and environment variables can override files or remote KV values. The effective configuration may therefore differ from what is stored on disk.

View source
SKILL.md:56In the instructionsOpen original file
Viper resolves a key by walking sources in this order (first set value wins):```1. explicit Set()      — viper.Set("key", val)    highest priority2. flag                — bound pflag.Flag3. env var             — BindEnv / AutomaticEnv4. config file         — ReadInConfig / MergeInConfig5. KV remote           — etcd / Consul6. default             — viper.SetDefault("key", val)   lowest priority```

The hot-reload guidance starts a background file watcher and explicitly recommends parsing, validating, and synchronizing shared configuration before applying it. This section includes protections against data races and replacing working state with invalid configuration.

View source
references/watch-and-reload.md:22In the instructionsOpen original file
`WatchConfig` starts a background goroutine that watches the config file using fsnotify. Call it after `ReadInConfig`.
references/watch-and-reload.md:93In the instructionsOpen original file
Always validate reloaded config before applying it — an invalid config mid-reload should keep the previous working config:```goviper.OnConfigChange(func(e fsnotify.Event) {    var candidate Config    if err := viper.Unmarshal(&candidate); err != nil {        log.Printf("reload: invalid config, keeping previous: %v", err)        return    }    if err := validate(candidate); err != nil {        log.Printf("reload: validation failed, keeping previous: %v", err)        return    }    applyConfig(candidate)})```
Start here · InstructionsSKILL.md
golang-spf13-viper
Lines connect the instruction file to its sections, not an observed execution order. Select a section to read the source. 5 more sections are available in the original file.

File reference map

References: 5
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 records7 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/binding-and-env.mdFull text included
  • references/sources-and-formats.mdFull text included
  • references/testing-and-isolation.mdFull text included
  • references/unmarshal.mdFull text included
  • references/watch-and-reload.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/binding-and-env.mdSupporting file
  • references/sources-and-formats.mdSupporting file
  • references/testing-and-isolation.mdSupporting file
  • references/unmarshal.mdSupporting file
  • references/watch-and-reload.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:31In the instructionsOpen original file
- [pkg.go.dev/github.com/spf13/viper](https://pkg.go.dev/github.com/spf13/viper)- [github.com/spf13/viper](https://github.com/spf13/viper)
SKILL.md:32In the instructionsOpen original file
- [pkg.go.dev/github.com/spf13/viper](https://pkg.go.dev/github.com/spf13/viper)- [github.com/spf13/viper](https://github.com/spf13/viper)
Run commands
SKILL.md:18In the instructionsOpen original file
    skill-library-version: "1.21.0"allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*paths:
SKILL.md:40In the instructionsOpen original file
```bashgo get github.com/spf13/viper@latest
Read files
evals/evals.json:64In the instructionsOpen original file
    "description": "Tests graceful handling of ConfigFileNotFoundError for optional config files",    "prompt": "My Go service uses viper to read a config file. When users run it without a config file, it crashes with 'Config File config not found in ...'. The config file should be optional. How do I fix this?",    "trap": "Without the skill, the model may suggest pre-checking if the file exists before calling ReadInConfig, or using os.Stat. The correct pattern is errors.As with viper.ConfigFileNotFoundError.",
evals/evals.json:320In the instructionsOpen original file
    "prompt": "I want my Go service to ship with a built-in default config file, but let ops teams drop an override.yaml in /etc/myapp/ to customize specific values without copying the whole config. How do I implement this layered loading?"     "trap": "Without the skill, the model may suggest reading only one file or writing custom merge logic. MergeInConfig is the viper primitive for this — base file first, then MergeInConfig for the override.",    "assertions": [
references/testing-and-isolation.md:8In the instructionsOpen original file
- [Injecting viper into your app](#injecting-viper-into-your-app)- [Reading config files in tests](#reading-config-files-in-tests)- [t.Setenv interactions](#tsetenv-interactions)
Change files
evals/evals.json:235In the instructionsOpen original file
        "id": "9.3",        "text": "Recommends testing hot-reload using direct writes (os.WriteFile) rather than editor saves"      },
references/watch-and-reload.md:32In the instructionsOpen original file
// reliable in tests:os.WriteFile("config.yaml", newContent, 0644)
Read keys or account settings
evals/evals.json:344In the instructionsOpen original file
    "description": "Tests BindEnv for env vars that don't follow the app prefix convention",    "prompt": "My Go service uses viper with SetEnvPrefix('MYAPP') and AutomaticEnv(). I also need to read GOOGLE_APPLICATION_CREDENTIALS from the environment and expose it as viper key 'google.credentials'. The prefix makes AutomaticEnv look for MYAPP_GOOGLE_CREDENTIALS. How do I bind to the exact env var name?",    "trap": "Without the skill, the model may suggest removing the prefix or reading via os.Getenv. BindEnv can bind a specific key to a specific env var name, bypassing the prefix.",
evals/evals.json:345In the instructionsOpen original file
    "prompt": "My Go service uses viper with SetEnvPrefix('MYAPP') and AutomaticEnv(). I also need to read GOOGLE_APPLICATION_CREDENTIALS from the environment and expose it as viper key 'google.credentials'. The prefix makes AutomaticEnv lo     "trap": "Without the skill, the model may suggest removing the prefix or reading via os.Getenv. BindEnv can bind a specific key to a specific env var name, bypassing the prefix.",    "assertions": [
evals/evals.json:349In the instructionsOpen original file
        "id": "14.1",        "text": "Uses viper.BindEnv(\"google.credentials\", \"GOOGLE_APPLICATION_CREDENTIALS\")"      },
Lines read
1,310
File checksum (to compare versions)
c4f91c232cce33d3b02a8ac685c1b9aaf6ba76d31d85da08000769a012c2cfe6