Skip to main content

minAgeDays

Rejects versions younger than a configured number of days. The intent is to let real users encounter (and report) a compromised package on the public ecosystem before your internal builds can pull it.

Configuration

- type: minAgeDays
days: "14"
exclude: "Mindbox.*;Quoka;Abc"
FieldTypeNotes
daysinteger (≥ 0)Minimum required age in whole days. Strings are accepted because YAML scalars from the configuration provider are weakly typed.
excludestring (optional);- or newline-separated list of glob patterns matched case-insensitively against the package ID. Matching packages bypass the age check (and the missing-published-date safeguard). Blank entries are ignored. Omit the field for no exclusions.

days: "0" is legal — it disables the rule but keeps the slot, useful for keeping config shapes stable between environments.

exclude — bypassing the age check

exclude lists package IDs (with * / ? glob wildcards, case-insensitive) that are trusted to skip the age requirement. Use it for first-party packages whose publishing pipeline you already control, or for vetted third-party IDs where the freshness check is not meaningful. The pattern syntax matches the allowDeny rule — Mindbox.* matches every package whose ID starts with Mindbox.; bare names like Quoka are exact matches.

A multi-line form is equivalent and is often easier to read in YAML:

- type: minAgeDays
days: "14"
exclude: |
Mindbox.*
Quoka
Abc

Note that an excluded match short-circuits the rule before the published-is-null safeguard runs — Heimdall trusts the exclusion list and will allow a matching package even if its catalog entry has no published timestamp.

Semantics

A version is allowed when:

now - catalogEntry.published >= days

The reference now is the request time captured in RuleContext.NowUtc, so evaluation is stable across all rules within a single request. The published timestamp comes from the NuGet v3 catalog entry of the upstream registration document.

published is null

If the upstream registration entry has no published timestamp (some unlisted versions, corrupted metadata), the rule denies the version. This is a safeguard: Heimdall cannot prove the age requirement, so it errs on the side of blocking.

Deny reasons

{
"ruleName": "minAgeDays",
"detail": "version published 0.3 days ago, requires 14"
}

The detail includes the actual age to one decimal place, so operators can quickly see whether a request was a hair short of the threshold or arrived on day zero.

When published is missing:

{
"ruleName": "minAgeDays",
"detail": "published date is missing"
}

Tuning

  • Production feeds: 7–14 days is a common floor. Long enough to catch most malicious-release reports, short enough that legitimate consumers don't notice.
  • CI for security updates: tighter, e.g. 1 day, on a separate feed reserved for Microsoft.AspNetCore.* or other vetted namespaces.
  • Hot reload: bumping the threshold from 14 to 30 is picked up on the next request without a restart; the cached registration documents (which carry the unfiltered version list and published timestamps) are re-evaluated against the new threshold.

What it does not do

  • It does not consult any CVE/vulnerability database.
  • It does not distinguish between prerelease and stable channels — the published timestamp is the only signal.
  • It does not care about SemVer ordering — a freshly-published 1.0.0 is treated identically to a freshly-published 2.0.0.
  • exclude does not combine with the allowDeny rule — they are independent stages of the filter pipeline. To deny a package outright, add an allowDeny rule alongside minAgeDays.