ScriptStack 1.0.5
Loading...
Searching...
No Matches
ScriptStack.Runtime.SafeClrPolicy Class Referencesealed

A conservative "safe" policy: allows access only to a small set of generally harmless BCL types and members, blocks reflection/IO/process/threading by default. More...

Inheritance diagram for ScriptStack.Runtime.SafeClrPolicy:
ScriptStack.Runtime.IClrPolicy

Public Member Functions

bool IsTypeAllowed (Type t)
bool IsMemberAllowed (MemberInfo m)
bool IsCallAllowed (MethodInfo m)
bool IsReturnValueAllowed (object? value)

Static Private Member Functions

static bool IsSafePrimitiveLike (Type t)
static bool IsBlockedNamespace (string? ns)

Detailed Description

A conservative "safe" policy: allows access only to a small set of generally harmless BCL types and members, blocks reflection/IO/process/threading by default.

This is intentionally restrictive. Extend/replace it for your use-case.

Definition at line 35 of file ClrPolicies.cs.

Member Function Documentation

◆ IsBlockedNamespace()

bool ScriptStack.Runtime.SafeClrPolicy.IsBlockedNamespace ( string? ns)
staticprivate

Definition at line 49 of file ClrPolicies.cs.

50 {
51 if (string.IsNullOrWhiteSpace(ns)) return false;
52
53 // Hard blocks: high-risk namespaces.
54 return ns.StartsWith("System.IO", StringComparison.Ordinal)
55 || ns.StartsWith("System.Reflection", StringComparison.Ordinal)
56 || ns.StartsWith("System.Diagnostics", StringComparison.Ordinal)
57 || ns.StartsWith("System.Runtime", StringComparison.Ordinal)
58 || ns.StartsWith("System.Threading", StringComparison.Ordinal)
59 || ns.StartsWith("System.Net", StringComparison.Ordinal)
60 || ns.StartsWith("Microsoft.Win32", StringComparison.Ordinal);
61 }

Referenced by IsTypeAllowed().

◆ IsCallAllowed()

bool ScriptStack.Runtime.SafeClrPolicy.IsCallAllowed ( MethodInfo m)

Implements ScriptStack.Runtime.IClrPolicy.

Definition at line 139 of file ClrPolicies.cs.

140 {
141 if (m == null) return false;
142
143 var declaring = m.DeclaringType;
144 if (declaring == null || !IsTypeAllowed(declaring)) return false;
145
146 // Block methods that open the door to reflection/unsafe access
147 if (m.Name.Equals("GetType", StringComparison.OrdinalIgnoreCase)) return false;
148 if (m.Name.Equals("GetHashCode", StringComparison.OrdinalIgnoreCase)) return true;
149 if (m.Name.Equals("ToString", StringComparison.OrdinalIgnoreCase)) return true;
150
151 // Only allow calls with safe parameter + return types
152 if (m.ReturnType != typeof(void) && !IsTypeAllowed(m.ReturnType)) return false;
153
154 foreach (var p in m.GetParameters())
155 {
156 if (!IsTypeAllowed(p.ParameterType)) return false;
157 }
158
159 // A small allowlist for common harmless string helpers
160 if (declaring == typeof(string))
161 {
162 string[] allowed =
163 {
164 "Contains", "StartsWith", "EndsWith", "Substring", "IndexOf", "Replace",
165 "ToUpper", "ToLower", "Trim", "TrimStart", "TrimEnd", "Split"
166 };
167 return allowed.Contains(m.Name, StringComparer.OrdinalIgnoreCase);
168 }
169
170 // Collections: allow basic operations only (Count is a property, indexers handled separately)
171 if (declaring.IsGenericType && declaring.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>))
172 {
173 string[] allowed = { "Add", "Remove", "RemoveAt", "Clear", "Contains" };
174 return allowed.Contains(m.Name, StringComparer.OrdinalIgnoreCase);
175 }
176
177 // Otherwise: deny.
178 return false;
179 }

References IsTypeAllowed().

◆ IsMemberAllowed()

bool ScriptStack.Runtime.SafeClrPolicy.IsMemberAllowed ( MemberInfo m)

Implements ScriptStack.Runtime.IClrPolicy.

Definition at line 106 of file ClrPolicies.cs.

107 {
108 if (m == null) return false;
109
110 // Block obvious footguns
111 if (m.Name.Equals("GetType", StringComparison.OrdinalIgnoreCase)) return false;
112
113 var declaring = m.DeclaringType;
114 if (declaring == null || !IsTypeAllowed(declaring)) return false;
115
116 if (m is PropertyInfo p)
117 {
118 // Only allow properties that are safe to read/write
119 if (!IsTypeAllowed(p.PropertyType)) return false;
120
121 // Indexer properties are handled by index access; still ensure safe parameter types
122 foreach (var ip in p.GetIndexParameters())
123 {
124 if (!IsTypeAllowed(ip.ParameterType)) return false;
125 }
126 return true;
127 }
128
129 if (m is FieldInfo f)
130 {
131 // fields: allow only safe types
132 return IsTypeAllowed(f.FieldType);
133 }
134
135 // other member kinds are not allowed here
136 return false;
137 }

References IsTypeAllowed().

◆ IsReturnValueAllowed()

bool ScriptStack.Runtime.SafeClrPolicy.IsReturnValueAllowed ( object? value)

Implements ScriptStack.Runtime.IClrPolicy.

Definition at line 181 of file ClrPolicies.cs.

182 {
183 if (value == null) return true;
184 if (value is NullReference) return true;
185
186 return IsTypeAllowed(value.GetType());
187 }

References IsTypeAllowed().

◆ IsSafePrimitiveLike()

bool ScriptStack.Runtime.SafeClrPolicy.IsSafePrimitiveLike ( Type t)
staticprivate

Definition at line 37 of file ClrPolicies.cs.

38 {
39 if (t.IsEnum) return true;
40 if (t.IsPrimitive) return true;
41 if (t == typeof(string)) return true;
42 if (t == typeof(decimal)) return true;
43 if (t == typeof(DateTime)) return true;
44 if (t == typeof(TimeSpan)) return true;
45 if (t == typeof(Guid)) return true;
46 return false;
47 }

Referenced by IsTypeAllowed().

◆ IsTypeAllowed()

bool ScriptStack.Runtime.SafeClrPolicy.IsTypeAllowed ( Type t)

Implements ScriptStack.Runtime.IClrPolicy.

Definition at line 63 of file ClrPolicies.cs.

64 {
65 if (t == null) return false;
66
67 if (IsSafePrimitiveLike(t)) return true;
68
69 if (t.IsArray)
70 return IsTypeAllowed(t.GetElementType()!);
71
72 if (IsBlockedNamespace(t.Namespace))
73 return false;
74
75 // Allow simple collection containers of safe types
76 if (t.IsGenericType)
77 {
78 var def = t.GetGenericTypeDefinition();
79 if (def == typeof(Nullable<>))
80 return IsTypeAllowed(Nullable.GetUnderlyingType(t)!);
81
82 if (def == typeof(System.Collections.Generic.List<>)
83 || def == typeof(System.Collections.Generic.IList<>)
84 || def == typeof(System.Collections.Generic.ICollection<>)
85 || def == typeof(System.Collections.Generic.IEnumerable<>))
86 {
87 return IsTypeAllowed(t.GetGenericArguments()[0]);
88 }
89
90 if (def == typeof(System.Collections.Generic.Dictionary<,>)
91 || def == typeof(System.Collections.Generic.IDictionary<,>))
92 {
93 var ga = t.GetGenericArguments();
94 return IsTypeAllowed(ga[0]) && IsTypeAllowed(ga[1]);
95 }
96 }
97
98 // Allow non-generic IList/IDictionary, but only as containers for safe values.
99 if (typeof(System.Collections.IList).IsAssignableFrom(t)) return true;
100 if (typeof(System.Collections.IDictionary).IsAssignableFrom(t)) return true;
101
102 // Everything else: deny.
103 return false;
104 }

References IsBlockedNamespace(), IsSafePrimitiveLike(), and IsTypeAllowed().

Referenced by IsCallAllowed(), IsMemberAllowed(), IsReturnValueAllowed(), and IsTypeAllowed().


The documentation for this class was generated from the following file: