cdk-nag, best practice checks that run inside your CDK app
Check CDK applications for best practices using a combination of available rule packs
At a glance
- What is it?
- cdk-nag is a CDK plugin that inspects a construct tree at synth time and reports violations from rule packs such as AWS Solutions, HIPAA Security, NIST 800-53 and PCI DSS. The v3 line moved the plugin and acknowledgement calls behind a new Validations API, and it keeps its audit trail in the cloud assembly.
- Who is it for?
- cdk-nag fits a CDK team that wants a compliance opinion in the same command that synthesizes the app, and it fits a security engineer who needs a recorded acknowledgement for every exception rather than a comment in a ticket.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A checker that runs before the template exists
The project checks CDK applications, and also CloudFormation templates, for best practices using a combination of available rule packs. It is inspired by cfn_nag, which is the useful clue about the approach, because the traditional way to audit a template is to point a separate scanner at the JSON after it has been produced. cdk-nag takes a different route. It is a plugin attached to the CDK application, so the checks run while the app is being synthesized, and the construct tree is what gets inspected, not a text file. The audience is a developer who wants the feedback in the same loop as the code, and a security or compliance engineer who wants a rule identifier attached to every finding. A team that has never run a CloudFormation scanner also gets a starting point, since the packs are chosen from well known compliance frameworks rather than invented locally.
Six pre-built packs and a set of rules without a home
The rule packs are listed in the README and detailed in RULES.md. There are six of them: AWS Solutions, HIPAA Security, NIST 800-53 revision 4, NIST 800-53 revision 5, PCI DSS 3.2.1, and Serverless. The presence of two separate NIST packs tells you the project tracks framework revisions rather than freezing a single interpretation, and the Serverless pack exists because many of the security rules in the other packs assume a persistent compute instance. There is also a category the README calls additional rules, which are not currently included in any of the pre-built NagPacks but remain available for inclusion in custom NagPacks. That category is the interesting part for an adopter, because it is where a team finds a check that is correct but not yet wired into a standard pack, and where the project documents how to build a pack of your own, with the NagPack developer docs in docs/NagPack.md. The full option list lives in NagPackProps in API.md.
Registering a pack under the v3 Validations API
The v3 usage pattern attaches a pack to the application with the Validations API that CDK provides, and the README shows that several packs can be attached to the same app.
import { App, Validations } from 'aws-cdk-lib';
import { AwsSolutionsChecks, NIST80053R5Checks } from 'cdk-nag';
declare const CdkTestStack: any;
const app = new App();
new CdkTestStack(app, 'CdkNagDemo');
// Simple rule informational messages using the AWS Solutions Rule pack
Validations.of(app).addPlugins(new AwsSolutionsChecks(app));
// Multiple rule packs can be run against the same app
Validations.of(app).addPlugins(new NIST80053R5Checks(app));Each pack is a class you construct with the app and then register. There is a verbose option, commented out in the README example, that adds explanations on the purpose of triggered rules, which is useful the first time a team runs a pack it did not write. The mechanism is a plugin attached at the application scope, so the checks apply to the whole tree beneath it, and combining the AWS Solutions pack with a NIST pack on the same app means one synthesise reports findings from both.
Acknowledging a rule, and acknowledging a single finding
Every checker of this kind produces findings you do not intend to fix, and cdk-nag handles that with the CDK's own acknowledgement mechanism rather than a comment. You acknowledge on a construct, and you give a reason, which is the part that matters for audit.
Validations.of(test).acknowledge({
id: 'AwsSolutions-EC23',
reason: 'This security group is used for internal testing only.',
});The same call works on a stack, and a stack level acknowledgement covers the findings inside it. The finer case comes with rules that report more than one finding per resource, such as IAM wildcard permissions. Each finding carries its own identifier in the format RuleId[FindingId], which is what the error output shows.
[Error at /StackName/rUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Action::s3:*]: The IAM entity contains wildcard permissions.
[Error at /StackName/rUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Resource::*]: The IAM entity contains wildcard permissions.So you can acknowledge the s3:* action and leave the Resource::* finding firing. That granularity is the difference between a mechanism that is usable in a real codebase and one that is not, because a rule that always fires on a wildcard IAM policy is a rule a team disables wholesale.
Raw overrides are invisible to the checker
The README documents a gap in the checking model that any adopter should know about. When an L2 construct has no native option to remediate an issue, the fix has to be applied through raw property overrides. Since raw overrides take place after template synthesis, those fixes are not caught by cdk-nag. The instruction is therefore to remediate the issue and acknowledge the rule, rather than to rely on the checker confirming the fix. The example makes the sequence concrete, adding a DisableApiTermination property override to the underlying CfnInstance and then acknowledging AwsSolutions-EC29 with a reason stating that the problem was remediated through a property override.
const cfnIns = instance.node.defaultChild as CfnInstance;
cfnIns.addPropertyOverride('DisableApiTermination', true);
Validations.of(instance).acknowledge({
id: 'AwsSolutions-EC29',
reason: 'Remediated through property override.',
});This is a real limitation rather than a defect, since the checker inspects the construct tree and a raw override is applied at a later stage, but it means the report tells you what the tree said, not what the template will contain.
The audit trail lives in the cloud assembly
By default, cdk-nag writes its violations to policy-validation-report.json in the cloud assembly, which is where a build pipeline can pick the findings up. The README also describes the v2 compatible path, the cdk_nag metadata block that can be written into synthesized CloudFormation templates for tools that expect it. Two output routes for the same findings is a sensible answer to a real split in the ecosystem, since the assembly is where CI tooling looks and the template metadata is where template consumers look. The repository carries a MIGRATION.md, which is the document to read if you are moving from cdk-nag v2, and the v3 line is the reason the API in the README differs from what most examples online still show. The rule identifiers are stable strings such as AwsSolutions-EC23 and AwsSolutions-IAM5, and the bracket suffix for a specific finding, which is what makes an acknowledgement record machine-checkable rather than free text.
One TypeScript project published in five languages
The packaging tells you how widely this is meant to be used. The project is authored by Amazon Web Services, published on npm, PyPI, Maven Central, NuGet and as a Go module, and it is listed on Construct Hub. The package.json scripts show the mechanism, with separate tasks named package:dotnet, package:go, package:java, package:js and package:python, all of them delegating to projen. The projenrc/ directory, the .projenrc.ts file and the projen-based scripts across the whole project mean the build, test and release process is generated rather than hand maintained, and the rosetta/ directory is the part that produces the multi language bindings. The Dockerfile for development inherits from jsii/superchain, and the .devcontainer.json plus pre-commit setup are part of the same generated workflow. Releases show the line at version 3: v3.0.0 on 2026-06-12, v3.0.1 on 2026-06-15 and v3.0.2 on 2026-08-04, with the last push on 2026-10-12. The licence is Apache-2.0, with a NOTICE file alongside it and copyright held by Amazon.
Editorial conclusion
cdk-nag fits a CDK team that wants a compliance opinion in the same command that synthesizes the app, and it fits a security engineer who needs a recorded acknowledgement for every exception rather than a comment in a ticket. It does not fit an organisation that needs an authoritative compliance attestation, since a rule pack is a checklist and the packs carry framework names rather than certification, and it does not fit a team still on cdk-nag v2 without reading MIGRATION.md first, because the plugin registration and acknowledgement calls changed. Verify three things before you adopt it: that the pack you enable matches the framework your auditor asks about, that the rules you intend to accept are ones you can defend, and whether your pipeline treats the policy-validation-report.json as the artifact of record.
Frequently asked questions
What is cdk-nag?
It is a CDK plugin that checks applications or CloudFormation templates for best practices using a combination of available rule packs. The packs cover AWS Solutions, HIPAA Security, NIST 800-53 revisions 4 and 5, PCI DSS 3.2.1 and Serverless.
How do I add cdk-nag to a CDK application?
Construct the pack with your app and register it through the CDK Validations API, for example Validations.of(app).addPlugins(new AwsSolutionsChecks(app)). The README shows that multiple rule packs can be run against the same app, and a verbose option adds explanations about triggered rules.
How do I suppress a cdk-nag finding I have accepted?
Use Validations.of on the construct or stack and call acknowledge with the rule id and a reason. For rules that report several findings per resource you can acknowledge one finding using the RuleId[FindingId] format, such as AwsSolutions-IAM5[Action::s3:*].
Where does cdk-nag write its findings?
By default it writes violations to policy-validation-report.json in the cloud assembly, and the README also describes writing the v2 compatible cdk_nag metadata block into synthesized CloudFormation templates.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cdklabs-cdk-nag)Was this useful?