Security policy
RuleWright treats a rule document as code-adjacent input. Rules decide business outcomes, so writing them is a privileged operation: review rule changes the way you review code, and don't load documents from people you haven't decided to trust. Within that assumption, the properties below are deliberate, and a break in any of them is a vulnerability.
Reporting a vulnerability
Report privately, not in a public issue. Open a security advisory on the repository, or email salwan@albahadly.com with "Security" in the subject.
Include the affected version and target framework, a rule document and a fact that reproduce the problem, and what you saw compared with what you expected. You can expect an acknowledgement within a week, then an assessment with a fix, or a rejection with reasons.
Supported versions
RuleWright is before 1.0. Fixes land in the latest release; there are no long-term support branches yet. Upgrade to get a fix.
What counts
A vulnerability is a break in any of these:
- Rules are pure data. The vocabulary is closed: operators, field paths and literals. RuleWright never compiles, evaluates or executes a string from a document. The only extension point is a
customfunction that the host application registered. - Evaluation is total. It doesn't throw on data. A null field, a missing key, a non-numeric operand and a division by zero each have defined results, so a hostile fact can't turn an evaluation into an exception path.
- Regular expressions are time-limited.
MatchesRegexruns against consumer data with a bounded timeout (one second by default, set withUseRegexTimeout) and raisesRegexMatchTimeoutExceptionrather than pinning a thread. - Nesting is bounded. The JSON readers cap depth at 64 by default, so a deeply nested document can't exhaust the stack while parsing.
- Numbers are finite. An out-of-range literal is rejected when the document is parsed, the same way on every target framework.
- Evaluation is stateless and thread-safe. One engine serves concurrent evaluations, and a fact never leaks into another evaluation.
Known limits, by design
These are documented behaviour, not defects. Know them before you widen who may write rules:
- The compiled-delegate cache is unbounded. It lives as long as the engine. A process that loads an unbounded number of distinct rules grows with them. Rebuild the engine periodically if rules are hot-reloaded at scale.
- Compilation cost scales with document size. Bound the size of the documents you accept.
- A
customfunction is host code. Its safety, thread safety and running time are yours. - Field paths read your fact. A rule can read any public property or field reachable from the fact you pass. Pass a projection built for the purpose, not a domain object with sensitive members hanging off it.
Accept rules you didn't write turns these into practice.