Skill Being Reviewed
Skill name: iac-security
Skill path: skills/cloud/iac-security/
False Positive Analysis
Benign Pulumi code that can be incorrectly flagged by literal/attribute-name scanning:
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const cfg = new pulumi.Config();
const dbPassword = cfg.requireSecret("dbPassword");
new aws.rds.Instance("db", {
allocatedStorage: 20,
engine: "postgres",
instanceClass: "db.t4g.micro",
username: "app",
password: dbPassword,
});
Why this is a false positive:
The current skill's detailed rule set is mostly Terraform/CloudFormation-shaped and relies heavily on literal patterns such as password, token, secret_key, and scanner-equivalent source checks. In Pulumi, a password property is not necessarily a committed secret or plaintext state value. When the value comes from requireSecret() / getSecret() or is wrapped with pulumi.secret(), Pulumi tracks the value as secret and encrypts it in state. The review should distinguish a plain config read from a Pulumi secret-tainted Output, otherwise valid code like the example above can be reported as a hardcoded-secret finding.
Benign Bicep code that can be over-reported as an admin-password secret:
@secure()
param adminPassword string
resource vm 'Microsoft.Compute/virtualMachines@2025-04-01' = {
name: 'safe-vm'
location: resourceGroup().location
properties: {
osProfile: {
computerName: 'safe-vm'
adminUsername: 'azureuser'
adminPassword: adminPassword
}
}
}
Why this is a false positive:
The presence of an adminPassword property is not by itself a finding in Bicep. Microsoft documents @secure() as the expected pattern for sensitive string/object parameters, and the Bicep linter's secure-input rule passes this pattern. The skill should ask whether the value is a secure parameter or secure output, not only whether a sensitive-looking property name exists.
Coverage Gaps
Missed variant 1: Pulumi plain config values passed into secret-bearing resource arguments
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const cfg = new pulumi.Config();
const dbPassword = cfg.require("dbPassword"); // not requireSecret()
new aws.ssm.Parameter("db-password", {
type: "SecureString",
value: dbPassword,
});
Why it should be caught:
This contains no literal password value in source, so the existing hardcoded-secret grep examples may not flag it. But Pulumi configuration is plain text by default unless set with --secret and read through secret APIs. The IaC review should check Pulumi config files (Pulumi.<stack>.yaml), SDK calls (require, get, requireSecret, getSecret), and resource argument flow into known sensitive fields.
Missed variant 2: Pulumi secret values exposed inside apply callbacks
const cfg = new pulumi.Config();
const apiToken = cfg.requireSecret("apiToken");
apiToken.apply((token) => {
console.log(`deploy token: ${token}`);
return token;
});
Why it should be caught:
Pulumi keeps secret outputs encrypted in state, but code inside an apply callback receives the plaintext value. Pulumi's own docs warn that the callback can still expose the plaintext value by printing it or writing it elsewhere. The current skill does not include Pulumi-specific secret-flow checks, so it can miss secret disclosure through logs, files, stack outputs, CI annotations, or custom provider code.
Missed variant 3: Bicep insecure parameters for secure properties
param adminPassword string
resource vm 'Microsoft.Compute/virtualMachines@2025-04-01' = {
name: 'unsafe-vm'
location: resourceGroup().location
properties: {
osProfile: {
computerName: 'unsafe-vm'
adminUsername: 'azureuser'
adminPassword: adminPassword
}
}
}
Why it should be caught:
This is not a literal hardcoded secret, so a simple string scanner may miss it. It is still insecure because a sensitive VM password is sourced from a non-secure Bicep parameter. The skill should include Bicep linter-equivalent checks for secure inputs, especially sensitive paths such as properties.osProfile.adminPassword.
Missed variant 4: Bicep outputs leaking list* values or secure parameters
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' existing = {
name: 'prodsa'
}
output primaryKey string = storage.listKeys().keys[0].value
Why it should be caught:
The current skill mentions CloudFormation NoEcho but does not model Bicep/ARM deployment-history leakage. Bicep outputs can expose values available through list* functions, and output values are visible in deployment history unless handled as secure output where supported. The review should check for outputs-should-not-contain-secrets patterns and require @secure() or no output for sensitive values.
Edge Cases
- Pulumi YAML uses
configuration.<key>.secret: true, not the same SDK syntax as TypeScript, Python, Go, .NET, or Java. The skill should cover all supported Pulumi languages it claims to review.
- Pulumi
additionalSecretOutputs can make provider-computed outputs secret even when the source code does not include a secret-looking input.
- Pulumi secret state protection depends on the configured secrets provider; a self-managed backend without a secure secrets provider changes the evidence needed.
- Bicep
@secure() is valid only for string/object parameters and, in newer Bicep versions, secure outputs. Arrays/numbers need wrapping or serialization rather than a direct secure decorator.
- Bicep deployment scripts and module outputs can leak secrets even when the top-level file uses secure parameters correctly.
Remediation Quality
Comparison to Other Tools
| Tool |
Catches this? |
Notes |
| Pulumi engine / Pulumi config |
Partial |
Tracks secret-tainted outputs, but reviewers still need to check plain config reads, callback leakage, stack outputs, and secrets provider posture. |
| Bicep linter |
Yes |
Has rules for secure values assigned to secure inputs and outputs that should not contain secrets. |
| Checkov / KICS |
Partial |
Can scan some Bicep/ARM and Terraform-like misconfigurations, but does not replace language-aware Pulumi secret-flow review. |
| tfsec / Trivy IaC |
Partial |
Strong Terraform coverage, weaker fit for Pulumi program semantics and Bicep secure decorators. |
Overall Assessment
Strengths:
- Good high-level coverage domains for IaC reviews.
- Useful Terraform state and provider-default pitfalls.
- Strong prompt-injection guidance for untrusted IaC comments and scanner suppressions.
Needs improvement:
- The claimed Pulumi and Bicep support is not backed by language-specific checks in
tool-rules.md.
- The hardcoded-secret guidance can over-report safe Pulumi/Bicep secret references and under-report unsafe non-literal secret flow.
- The output format does not capture Pulumi secret-taint evidence, Pulumi secrets provider posture, Bicep secure parameter/output evidence, or Bicep linter rule coverage.
Priority recommendations:
- Add a Pulumi section covering
requireSecret / getSecret, pulumi.secret, additionalSecretOutputs, plain Config.require, apply callback leakage, stack outputs, and secrets provider configuration.
- Add Bicep checks for
@secure() parameters, secure outputs, list* output leakage, deployment history exposure, and secure-input linter rules.
- Add an evidence-origin field per finding:
Terraform source, Terraform plan, CloudFormation, Pulumi SDK, Pulumi stack config, Bicep source, Bicep linter, or Not Evaluable.
- Add benign/vulnerable examples for Pulumi TypeScript/Python and Bicep so reviewers do not apply Terraform-only heuristics to different IaC languages.
Sources Checked
Bounty Info
Skill Being Reviewed
Skill name:
iac-securitySkill path:
skills/cloud/iac-security/False Positive Analysis
Benign Pulumi code that can be incorrectly flagged by literal/attribute-name scanning:
Why this is a false positive:
The current skill's detailed rule set is mostly Terraform/CloudFormation-shaped and relies heavily on literal patterns such as
password,token,secret_key, and scanner-equivalent source checks. In Pulumi, apasswordproperty is not necessarily a committed secret or plaintext state value. When the value comes fromrequireSecret()/getSecret()or is wrapped withpulumi.secret(), Pulumi tracks the value as secret and encrypts it in state. The review should distinguish a plain config read from a Pulumi secret-taintedOutput, otherwise valid code like the example above can be reported as a hardcoded-secret finding.Benign Bicep code that can be over-reported as an admin-password secret:
Why this is a false positive:
The presence of an
adminPasswordproperty is not by itself a finding in Bicep. Microsoft documents@secure()as the expected pattern for sensitive string/object parameters, and the Bicep linter's secure-input rule passes this pattern. The skill should ask whether the value is a secure parameter or secure output, not only whether a sensitive-looking property name exists.Coverage Gaps
Missed variant 1: Pulumi plain config values passed into secret-bearing resource arguments
Why it should be caught:
This contains no literal password value in source, so the existing hardcoded-secret grep examples may not flag it. But Pulumi configuration is plain text by default unless set with
--secretand read through secret APIs. The IaC review should check Pulumi config files (Pulumi.<stack>.yaml), SDK calls (require,get,requireSecret,getSecret), and resource argument flow into known sensitive fields.Missed variant 2: Pulumi secret values exposed inside
applycallbacksWhy it should be caught:
Pulumi keeps secret outputs encrypted in state, but code inside an
applycallback receives the plaintext value. Pulumi's own docs warn that the callback can still expose the plaintext value by printing it or writing it elsewhere. The current skill does not include Pulumi-specific secret-flow checks, so it can miss secret disclosure through logs, files, stack outputs, CI annotations, or custom provider code.Missed variant 3: Bicep insecure parameters for secure properties
Why it should be caught:
This is not a literal hardcoded secret, so a simple string scanner may miss it. It is still insecure because a sensitive VM password is sourced from a non-secure Bicep parameter. The skill should include Bicep linter-equivalent checks for secure inputs, especially sensitive paths such as
properties.osProfile.adminPassword.Missed variant 4: Bicep outputs leaking
list*values or secure parametersWhy it should be caught:
The current skill mentions CloudFormation
NoEchobut does not model Bicep/ARM deployment-history leakage. Bicep outputs can expose values available throughlist*functions, and output values are visible in deployment history unless handled as secure output where supported. The review should check foroutputs-should-not-contain-secretspatterns and require@secure()or no output for sensitive values.Edge Cases
configuration.<key>.secret: true, not the same SDK syntax as TypeScript, Python, Go, .NET, or Java. The skill should cover all supported Pulumi languages it claims to review.additionalSecretOutputscan make provider-computed outputs secret even when the source code does not include a secret-looking input.@secure()is valid only for string/object parameters and, in newer Bicep versions, secure outputs. Arrays/numbers need wrapping or serialization rather than a direct secure decorator.Remediation Quality
Comparison to Other Tools
Overall Assessment
Strengths:
Needs improvement:
tool-rules.md.Priority recommendations:
requireSecret/getSecret,pulumi.secret,additionalSecretOutputs, plainConfig.require,applycallback leakage, stack outputs, and secrets provider configuration.@secure()parameters, secure outputs,list*output leakage, deployment history exposure, and secure-input linter rules.Terraform source,Terraform plan,CloudFormation,Pulumi SDK,Pulumi stack config,Bicep source,Bicep linter, orNot Evaluable.Sources Checked
Bounty Info