fix(security): deny Environment/GC and ADO.NET provider namespaces; close reflection-gateway list (GetTypes/EntryPoint/Declared*/DynamicInvoke)

Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
Joseph Doherty
2026-07-09 15:38:12 -04:00
parent dbd3ed2fc7
commit d19ab93d39
4 changed files with 80 additions and 3 deletions
@@ -321,4 +321,29 @@ public class ScriptTrustValidatorTests
var code = "var s = \"System.IO.File.ReadAllText\";";
Assert.Empty(ScriptTrustValidator.FindViolations(code));
}
// ---- PLAN-05 Task 21: hardened deny-list additions -----------------------
// Environment (whole type), GC, and the concrete ADO.NET provider namespaces
// (Microsoft.Data / System.Data.SqlClient / .Odbc / .OleDb) are now forbidden.
[Theory]
[InlineData("Environment.Exit(0);")]
[InlineData("Environment.FailFast(\"x\");")]
[InlineData("var s = Environment.GetEnvironmentVariable(\"SCADABRIDGE_API_KEY\");")]
[InlineData("var c = new Microsoft.Data.SqlClient.SqlConnection(\"Server=attacker\");")]
public void FindViolations_Flags(string code) => Assert.NotEmpty(ScriptTrustValidator.FindViolations(code));
// Syntactic gateway closure (matters in TPA-degraded fallback mode): these
// reflection-gateway members are rejected regardless of receiver.
[Theory]
[InlineData("typeof(string).Assembly.GetTypes()")]
[InlineData("asm.EntryPoint")]
public void SyntacticPass_Flags(string code) => Assert.NotEmpty(ScriptTrustValidator.FindViolations(code));
// Must NOT regress legitimate scripts: Task.Delay stays allowed and
// delegate.Invoke() is deliberately NOT on the reflection-gateway list.
[Theory]
[InlineData("await Task.Delay(1);")]
[InlineData("Func<int,int> f = x => x; f.Invoke(3);")]
public void FindViolations_Allows(string code) => Assert.Empty(ScriptTrustValidator.FindViolations(code));
}