aws / aws/aws-cdk

aws-ec2: invalid or missing CIDR mask reports "NaN.NaN.NaN.NaN is not a valid IP Address", and /33 silently produces a wrong block

Open Beginner friendly
#38,523 1 comment 0 reactions 0 assignees View on GitHub
@aws-cdk/aws-ec2 bug effort/small p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
2d 3h
Merged PRs (30d)
83

Description

### Describe the bug

An invalid or missing CIDR mask is never validated, so it flows into the address arithmetic in `CidrBlock` and surfaces as an error naming an IP address the caller never wrote — or, for a mask above 32, produces a nonsensical block with no error at all.

Forgetting the mask is an easy mistake, and the resulting message gives no hint that the mask is the problem:

```
ec2.IpAddresses.cidr('10.0.0.0')
-> Error: NaN.NaN.NaN.NaN is not a valid IP Address
```

Nothing in that message points at the missing `/16`.

Full behaviour of `IpAddresses.cidr()` on aws-cdk-lib 2.263.0:

| input | result |
|---|---|
| `'10.0.0.0'` (no mask) | ❌ `NaN.NaN.NaN.NaN is not a valid IP Address` |
| `'10.0.0.0/'` | ❌ `NaN.NaN.NaN.NaN is not a valid IP Address` |
| `'10.0.0.0/abc'` | ❌ `NaN.NaN.NaN.NaN is not a valid IP Address` |
| `'10.0.0.0/-1'` | ❌ `512.0.0.0 is not a valid IP Address` |
| `'10.0.0.0/33'` | ⚠️ **no error** — silently becomes `9.255.255.255/33` |

The `/33` row is the worst of these: `new CidrBlock('10.0.0.0/33')` returns a block whose `cidr` is `9.255.255.255/33`, an address outside the range the caller asked for, and synthesis continues. The failure only appears later — either as a confusing downstream error (`1 of /24 exceeds remaining space of 9.255.255.255/33`) or at deploy time from CloudFormation.

### Expected Behavior

An invalid mask should fail fast with an error that names the mask as the problem and states the accepted range, per the repo's error-message guidance (include the wrong value, the expected values, and what to change). Something like:

```
invalid CIDR mask in "10.0.0.0", expected an integer between 0 and 32 after a '/', e.g. '10.0.0.0/16'
```

### Current Behavior

The mask is read with `parseInt` and used without any validation:

```ts
// packages/aws-cdk-lib/aws-ec2/lib/network-util.ts
this.mask = parseInt(ipAddressOrCidr.split('/')[1], 10);
this.networkAddress = NetworkUtils.ipToNum(ipAddressOrCidr.split('/')[0]) +
CidrBlock.calculateNetsize(this.mask) - 1;
```

With no mask, `parseInt(undefined, 10)` is `NaN`, so `calculateNetsize` returns `2 ** (32 - NaN)` = `NaN`, `networkAddress` becomes `NaN`, and `numToIp` finally reports `NaN.NaN.NaN.NaN`. With `/33`, `calculateNetsize` returns `0.5`, and the block silently resolves one address below the input.

### Reproduction Steps

```ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

const app = new cdk.App();
const stack = new cdk.Stack(app, 'S');

// Forgot the mask
new ec2.Vpc(stack, 'V', {
ipAddresses: ec2.IpAddresses.cidr('10.0.0.0'), // -> NaN.NaN.NaN.NaN is not a valid IP Address
});
```

Or, isolating the mask handling with no CDK app at all — this is the exact arithmetic from `network-util.ts`:

```js
const mask = parseInt('10.0.0.0'.split('/')[1], 10); // NaN
const netsize = 2 ** (32 - mask); // NaN
// -> networkAddress NaN -> numToIp(NaN) -> 'NaN.NaN.NaN.NaN'

const mask33 = parseInt('10.0.0.0/33'.split('/')[1], 10); // 33
const netsize33 = 2 ** (32 - mask33); // 0.5 <-- half an address
```

### Possible Solution

Validate the mask in the `CidrBlock` constructor before it reaches the arithmetic, and throw an `UnscopedValidationError` naming the mask.

Keeping `parseInt` semantics for the parse itself matters for backwards compatibility: `'10.0.0.0/16abc'` and `'10.0.0.0/16.5'` resolve to `16` today and synthesize successfully, so they must keep working. Only masks that cannot produce a usable block (`NaN`, `< 0`, `> 32`) should be rejected. Under that rule no input that synthesizes today changes behaviour:

| input | before | after |
|---|---|---|
| `10.0.0.0/16` | `10.0.0.0/16` | `10.0.0.0/16` |
| `0.0.0.0/0` | `0.0.0.0/0` | `0.0.0.0/0` |
| `10.0.0.1/32` | `10.0.0.1/32` | `10.0.0.1/32` |
| `10.0.0.0/16abc` | `10.0.0.0/16` | `10.0.0.0/16` |
| `10.0.0.0/16.5` | `10.0.0.0/16` | `10.0.0.0/16` |
| `10.0.0.0/33` | `9.255.255.255/33` | clear error |
| `10.0.0.0/-1` | `512.0.0.0 is not a valid IP Address` | clear error |
| `10.0.0.0` | `NaN.NaN.NaN.NaN is not a valid IP Address` | clear error |

The only rows that change are ones that already failed, or that produced a block CloudFormation would reject — so no feature flag is needed under the contributing guidance for validation changes.

### Other Information

Related but distinct: #34784 covers misaligned *base addresses* being silently rounded up (`10.0.3.1/28` → `10.0.3.16/28`). This issue is about the *mask*, and is unaffected by that one.

Separately, and not proposed for change here: the octet check in `NetworkUtils.validIp` uses `parseInt` per octet, so `'1.2.3.1e2/16'` is accepted and synthesizes a VPC with CidrBlock `1.3.0.0/16`. Tightening that would reject input that currently deploys, so it would need a feature flag — I've left it out to keep this to one concern.

### CDK CLI Version

N/A (synthesis-time, framework only)

### Framework Version

aws-cdk-lib 2.263.0

### Node.js Version

v24.1.0

### OS

macOS 15 (Darwin 25.2.0)

### Language

TypeScript

Contributor guide

Open the contributing guide

Research direction

Start in packages/aws-cdk-lib/aws-ec2/lib/network-util.ts at the CidrBlock constructor and its callers such as IpAddresses.cidr(). Reproduce the listed missing, negative, and over-32 masks, then add focused regression coverage; done means invalid masks fail with a clear range-bearing validation error while existing parseInt-compatible masks still synthesize.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
cloud, networking
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.