Docs

Authoring Custom Rules

On Growth and above, your org can author its own UiPath risk-detection rules. A custom rule runs inside the same analyzer as the built-in rules — on every member's validation and every CI check — and its findings appear alongside the rest. Rules are JSON; the in-app editor builds that JSON for you, and this page is the reference behind it.

Anatomy of a rule

A rule matches an activity and, optionally, asserts conditions on that activity's properties. Here is a complete rule that flags an InvokeWorkflowFile activity which suppresses errors:

{
  "id": "ORG-NO-CONTINUE",
  "platform": "uipath",
  "name": "No ContinueOnError on InvokeWorkflowFile",
  "severity": "high",
  "message": "InvokeWorkflowFile must not suppress errors with ContinueOnError.",
  "enabled": true,
  "match": {
    "activity": "*.InvokeWorkflowFile",
    "conditions": [
      { "property": "ContinueOnError", "equals": "True" }
    ]
  }
}
FieldRulesDescription
id^[A-Z][A-Z0-9-]{2,31}$, unique per org, may not start with FC-Stable identifier. Surfaces on every finding this rule produces.
platformuipath only (v1)The automation platform the rule targets. Other platforms are rejected for now.
namerequiredShort human label shown in the editor and rule list.
severitylow · medium · high · criticalThe severity stamped on every finding. Declared severity is final (no elevation).
messagerequired, ≤ 500 charsThe finding text an engineer reads. Say what is wrong and what to do.
enabledbooleanDisabled rules are stored but never evaluated.
match.activityrequired, ≤ 200 charsActivity type/name pattern, with * wildcards. See below.
match.conditionsoptional listProperty assertions, all AND-combined. Empty list matches every activity of that type.

Matching activities

match.activity is matched against each activity's type/name in the workflow. A * stands for any run of characters, so *.InvokeWorkflowFile matches the InvokeWorkflowFile activity regardless of its namespace prefix, and *Click* matches any activity whose name contains Click. A pattern with no * must match the whole name. Matching is case-sensitive on the activity name and ignores the activity's DisplayName (use a condition on DisplayName if you need that).

Conditions

Each condition names a property (resolved against the activity's XAML attributes — ContinueOnError, TimeoutMS, WorkflowFileName, DisplayName, …) and exactly one match-type. All conditions on a rule must hold for the activity to be flagged.

Match-typeFires when
{ "exists": true }The attribute is present on the activity.
{ "notExists": true }The attribute is absent.
{ "equals": "True" }The attribute value equals the given string, case-insensitively.
{ "contains": "http://" }The attribute value contains the given substring.
{ "regex": ".*Prod.*" }The attribute value matches the given .NET regular expression.

Composite rules (where)

For rules that a flat condition list can't express, replace match.conditions with a match.where expression tree. A node sets exactly one of the keys below; where and conditions are mutually exclusive on a rule.

NodeMatches when
{ "allOf": [ … ] }Every child node matches.
{ "anyOf": [ … ] }At least one child node matches.
{ "not": { … } }The child node does not match.
{ "attribute": { … } }A condition (the same property + match-type shape) holds on the activity.
{ "child": { "element": "*.Text", "where": … } }A descendant element matching the name pattern exists (and satisfies its optional nested where). Use for properties expressed as child elements.
{ "notInsideAncestor": "TryCatch" }The activity has no ancestor activity matching the pattern. Combine with not to require the opposite.
{ "siblingBefore": "*.LogMessage" }An activity matching the pattern appears earlier under the same parent. siblingAfter checks the other direction.

Structural checks (notInsideAncestor, siblingBefore, siblingAfter) always resolve against the activity matched by match.activity — even when nested inside a child block, where attribute checks instead apply to the matched child element.

Hardcoded path that isn't wrapped in a Try/Catch

{
  "id": "ORG-INVOKE-UNGUARDED",
  "platform": "uipath",
  "name": "Hardcoded workflow path not wrapped in a Try/Catch",
  "severity": "high",
  "message": "InvokeWorkflowFile with an absolute path must run inside a Try/Catch.",
  "enabled": true,
  "match": {
    "activity": "*.InvokeWorkflowFile",
    "where": {
      "allOf": [
        { "attribute": { "property": "WorkflowFileName", "regex": "^[A-Za-z]:\\\\" } },
        { "not": { "notInsideAncestor": "TryCatch" } }
      ]
    }
  }
}

Author composite rules in the dashboard's Advanced (JSON) editor (rules with a where tree open there automatically), or ship them in a YAML pack imported via the app or rpagov rules import.

Limits & safety

LimitValue
Rules per org50
message length≤ 500 characters
match.activity length≤ 200 characters
where nesting depth≤ 5 levels
where nodes per rule≤ 40
regex length≤ 500 characters, and it must compile
Regex evaluationBounded to 100 ms per match (ReDoS guard); a timeout counts as no match.
Score impactNone in v1 — custom findings surface in lists, counts, and exports but do not change the health score.

More examples

Flag an environment-specific path (regex)

{
  "id": "ORG-PROD-PATH",
  "platform": "uipath",
  "name": "Environment-specific path in InvokeWorkflowFile",
  "severity": "medium",
  "message": "Avoid hardcoded environment paths; resolve the workflow from a config asset.",
  "enabled": true,
  "match": {
    "activity": "*.InvokeWorkflowFile",
    "conditions": [
      { "property": "WorkflowFileName", "regex": ".*Prod.*" }
    ]
  }
}

Require an explicit timeout (notExists)

{
  "id": "ORG-REQUIRE-TIMEOUT",
  "platform": "uipath",
  "name": "Click without an explicit timeout",
  "severity": "low",
  "message": "Set TimeoutMS on Click activities so a missing target cannot hang the run.",
  "enabled": true,
  "match": {
    "activity": "*.Click",
    "conditions": [
      { "property": "TimeoutMS", "notExists": true }
    ]
  }
}

Write your first rule

The fastest way in is the editor: in the dashboard go to Governance → Custom Rules, fill in the form, and test the draft against a real .xaml before you save — it shows exactly which activities the rule would flag. Saved rules take effect on the next validation for everyone in the org.

Browse the built-in rules in the rule library, or talk to us if you want a rule reviewed.