
.NET 7 fork of seal-security-nuget-demo: same CVE-2024-21907 exploit story, retargeted for customers locked to .NET SDK 7.
This is a retargeted fork of the canonical seal-security-nuget-demo (which targets net9.0). The exploit story, the controllers, and the sealed-package list are identical — only the TargetFramework differs.
It exists because most enterprise customers can't move to the newest .NET SDK on demand. .NET 7 reached end-of-support on May 14, 2024, but real production estates still ship on it for compatibility, certification, or operational reasons. That is precisely the case Seal Security is designed for: when a customer can't (or won't) take a major version bump, Seal patches the vulnerable dependency in place under the same version, with no public API change and no code edits to the customer's app. This demo lets that conversation happen on the customer's actual stack instead of asking them to install net8/net9 first.
The fork pins the SDK to 7.0.x via global.json so accidental upgrades don't sneak in during the demo.
This demo application is a simple ASP.NET Core welcome page that uses Newtonsoft.Json 12.0.2 to parse user input as a config object. The app has a name field — type your name, click Go, and it displays "Welcome, alice!". Under the hood it passes the input through Newtonsoft.Json's JsonConvert.DeserializeObject<NestedConfig>(). That's it — completely standard usage of a popular JSON library.
The problem is that Newtonsoft.Json 12.0.2 (and versions before 13.0.1) has CVE-2024-21907 — a high severity Denial of Service vulnerability with a CVSS score of 7.5 (HIGH). This demo shows how Seal Security patches the vulnerability in-place without requiring a major version upgrade.
Newtonsoft.Json's JsonConvert.DeserializeObject<T>() method can be exploited by crafting deeply nested JSON payloads. When deserializing into a typed object (POCO), the library's JsonSerializerInternalReader performs truly recursive calls (CreateValueInternal → CreateObject → PopulateObject → SetPropertyValue → CreateValueInternal) that cause stack overflow, leading to application crash (Denial of Service).
The app takes user input and parses it through Newtonsoft.Json. If the input is a URL, the app fetches the content first — a realistic pattern used by config loaders, API testers, and webhook receivers:
public class NestedConfig
{
[JsonProperty("n")]
public NestedConfig? N { get; set; }
}
var config = JsonConvert.DeserializeObject<NestedConfig>(name);
Normal input: Type alice → displays "Welcome, alice!"
Exploit: Paste this URL into the name field and click Go:
https://raw.githubusercontent.com/seal-sec-demo-2/json-payload/main/payload.json
The app detects it's a URL, fetches the json-payload (deeply nested JSON {"n":{"n":{...}}}), and deserializes it through Newtonsoft.Json into the recursive NestedConfig class — triggering the stack overflow.
The JsonSerializerInternalReader recurses through CreateValueInternal → CreateObject → PopulateObject → SetPropertyValue for every nesting level. At ~5,000 levels deep, this exhausts the thread stack and the application crashes with a StackOverflowException — the process dies instantly (no graceful error handling possible).
With this vulnerability, attackers can:
The publicly available fix requires upgrading to version 13.0.1. However, upgrading major versions often introduces:
This makes the "just upgrade" fix a project that can easily take weeks of developer time — leaving the vulnerability open in the meantime.
Seal's patched version (12.0.2-sp1) adds recursion depth protection without changing any public API. The patch:
MaxDepth limits to prevent unbounded recursionThis is the same mitigation strategy applied in Newtonsoft.Json 13.0.1, backported to 12.0.2 as a drop-in replacement.
This demo also includes other vulnerable NuGet packages that Seal Security can patch:
XML External Entity (XXE) vulnerability in log4net's XML configuration parsing. An attacker who can control the log4net configuration file can:
Note on
System.Net.Http: The canonical net9 demo also ships a vulnerableSystem.Net.Http 4.3.0reference for CVE-2017-0249. We've omitted it from this net7 fork because on .NET 7System.Net.Httpis part of the BCL and the standalone package reference is a vestigial meta-package — it has known edge cases withdotnet add package --source <local-nupkg>, which is exactly how the Seal CLI applies sealed versions. Dropping it makes theseal fixstep reliable without changing the demo's story (HttpClientstill works fine; the runtime supplies it).
Windows CLI binaries were discontinued after v0.3.238. v0.3.238 is fully functional for NuGet remediation on Windows.
A detailed Windows Server install + run guide is in README-WINDOWS-SERVER.md. The Quick Start below covers the same steps in condensed form.
PowerShell:
$env:SEAL_TOKEN = "your-seal-token-here"
$env:SEAL_PROJECT = "nuget-demo-net7"
cd seal-security-nuget-demo-net7
# Restore (pulls from nuget.org and the Seal feed — see nuget.config)
dotnet restore
# Build and run
dotnet build
dotnet run
Open http://localhost:5000 — the app is running with vulnerable dependencies.
Type alice in the name field, click Go. You should see: "Welcome, alice!"
Paste the following URL into the name field and click Go:
https://raw.githubusercontent.com/seal-sec-demo-2/json-payload/main/payload.json
Unpatched result: Browser shows an error / connection reset — the app crashed with a StackOverflowException in JsonSerializerInternalReader.CreateValueInternal. The process is dead.
# (Optional — already done above) Restore dependencies first
dotnet restore
# Run Seal CLI to fix vulnerabilities
seal fix . --mode remote -v
# Restore again to pull sealed versions
dotnet restore
# Build and run the patched app
dotnet build
dotnet run
The app now uses patched versions (Newtonsoft.Json 12.0.2-sp1, log4net 2.0.5-sp1).
Patched result: Paste the same exploit URL → the page shows "Blocked by Seal patch: MaxDepth of 64 has been exceeded." — Newtonsoft.Json's patched recursion limit rejected the deep payload. The server continues running normally.
dotnet list package
You should see packages with -sp1 suffix indicating Seal Security patches.
The CLI step must be added immediately after dependencies are installed but before the final build.
# 1. Restore dependencies
dotnet restore
# 2. <--- Run Seal CLI Here
$env:SEAL_TOKEN = "your-seal-token-here"
$env:SEAL_PROJECT = "nuget-demo-net7"
seal fix . --mode remote -v
# 3. Restore again (to get sealed versions)
dotnet restore
# 4. Build
dotnet build
| Mode | Description |
|---|---|
all | Apply all available fixes automatically |
remote | Only apply fixes approved in the Seal UI |
local | Only apply fixes defined in .seal-actions.yml |
.seal-actions.yml in this repo already lists the three sealed overrides for local mode, so seal fix . --mode local -v works offline (still needs token for the artifact server).
nuget.config is pre-configured to use Seal Security with environment variables:
<configuration>
<packageSources>
<add key="Seal" value="https://nuget.sealsecurity.io/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceCredentials>
<Seal>
<add key="Username" value="%SEAL_PROJECT%" />
<add key="ClearTextPassword" value="%SEAL_TOKEN%" />
</Seal>
</packageSourceCredentials>
</configuration>
| Variable | Description |
|---|---|
SEAL_TOKEN | Your Seal Security access token |
SEAL_PROJECT | Project ID (e.g., nuget-demo-net7) |
The Seal CLI needs outbound HTTPS (TCP 443) to:
cli.sealsecurity.io — scan / fix configurationauthorization.sealsecurity.io — token validationnuget.sealsecurity.io — sealed .nupkg downloadsd2zko6i8myndc4.cloudfront.net — CDN that serves the actual sealed artifacts (the .sealsecurity.io hostnames redirect here)api.nuget.org / standard nuget.org endpoints — for non-sealed dependenciesVerify from PowerShell after the firewall is opened:
Test-NetConnection cli.sealsecurity.io -Port 443
Test-NetConnection authorization.sealsecurity.io -Port 443
Test-NetConnection nuget.sealsecurity.io -Port 443
Test-NetConnection d2zko6i8myndc4.cloudfront.net -Port 443
All should report TcpTestSucceeded: True.
12.0.2-sp1 is a binary-compatible drop-in for 12.0.2.Packages used by this demo:
| Package | Vulnerable Version | Sealed Version | CVE | CVSS |
|---|
Other sealed NuGet packages available from the Seal feed (not in this demo, listed for reference):
MIT License - See LICENSE file for details.
| Item | Why it matters |
|---|
global.json pins SDK to 7.0.x with rollForward: latestFeature | Stops machines with side-by-side net8/net9 from silently switching SDKs mid-demo. |
System.Configuration.ConfigurationManager pinned to 7.0.0 | The canonical net9 demo uses 8.0.0, which targets net8 only and fails to restore on net7. 7.0.0 has the same API surface log4net needs. |
NU1701 suppressed in the csproj | log4net 2.0.5 advertises a legacy net4x TFM that .NET 7 accepts at runtime but warns about at restore. The warning is cosmetic; suppression keeps build output clean during the demo. |
| Seal CLI v0.3.238 for Windows x64 | Last release with a Windows binary; fully functional for NuGet remediation. Windows binaries were discontinued after this version, so do not suggest a newer release. |
| Newtonsoft.Json | 12.0.2 | 12.0.2-sp1 | CVE-2024-21907 | 7.5 HIGH |
| log4net | 2.0.5 | 2.0.5-sp1 | CVE-2018-1285 | 9.8 CRITICAL |
| Package | Vulnerable Version | Sealed Version | CVE | CVSS |
|---|
| log4net | 2.0.0 | 2.0.0-sp1 | CVE-2018-1285 | 9.8 CRITICAL |
| System.Net.Http | 4.3.0 | 4.3.0-sp1 | CVE-2017-0249 | 7.3 HIGH |
| Snappier | 1.1.0 | 1.1.0-sp1 | CVE-2023-28638 | 7.0 HIGH |
| jQuery.Validation | 1.17.0 | 1.17.0-sp1 | CVE-2021-21252 | 7.5 HIGH |