From 8cb219e20a0c7d465b7d8455ccace49c3dfe174e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:54:16 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM]=20?= =?UTF-8?q?Add=20input=20validation=20to=20Duck=20extension?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: timonkrebs <11026852+timonkrebs@users.noreply.github.com> --- .jules/sentinel.md | 5 +++++ src/NTypeForge/DuckExtensions.cs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index f5cf3bd..68efa39 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -2,3 +2,8 @@ **Vulnerability:** Source Generator `NTypeForge.SourceGenerator` was always emitting `public static class` for its duck-typing extensions. If the type being ducked (`target`) was `internal`, this created a `CS0051: Inconsistent accessibility` compiler error and essentially violated the principle of least privilege, potentially leaking internal types into public scope. **Learning:** Source Generators creating types meant to be used alongside user code should dynamically match the accessibility of their targets (or default to `internal` if appropriate for their use-case) to prevent scope leakage. **Prevention:** Check `DeclaredAccessibility == Accessibility.Public` (or effective accessibility for nested types) on the target type, and emit `internal static class` instead of `public static class` when the target is not public. + +## 2026-07-08 - [Fail Securely] Validate public API inputs explicitly +**Vulnerability:** The public API `Duck(this object instance)` did not validate its `instance` input for null. If null was passed, it would bypass the type check and throw a misleading `InvalidOperationException` intended for missing generator proxies. This obscures root causes and could potentially lead to unexpected application state. +**Learning:** Relying on downstream operations (or subsequent logic) to throw generic exceptions on null input is unsafe and confusing. Always validate input immediately at the entry point of a public API. +**Prevention:** Use `ArgumentNullException.ThrowIfNull()` at the very start of public-facing API methods to fail fast, securely, and with accurate error information. diff --git a/src/NTypeForge/DuckExtensions.cs b/src/NTypeForge/DuckExtensions.cs index 8909539..b0bb973 100644 --- a/src/NTypeForge/DuckExtensions.cs +++ b/src/NTypeForge/DuckExtensions.cs @@ -65,6 +65,8 @@ public static bool TryUnbox(this object? proxy, out T value) /// public static T Duck(this object instance) where T : class { + ArgumentNullException.ThrowIfNull(instance); + if (instance is T t) return t; throw new InvalidOperationException("NTypeForge: Duck was called but no proxy was generated. Ensure the NTypeForge source generator is running and the target type matches the interface.");