You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
The safety policy hands off a Shopify order note as "moving money" while refunds pass #890
Writing a note on a Shopify order (SHOPIFY_UPDATE_ORDER with only id and note) is handed off to the person as a money action:
approval.evaluated composio-shopify/SHOPIFY_UPDATE_ORDER
outcome: { behaviour: "hand_off", source: "safety",
reason: "Paying, purchasing or moving money is always done by the person." }
Meanwhile SHOPIFY_CREATE_REFUND, which does move money, passes without a hand-off.
The payments rule in server/src/approvals/policy.ts is a keyword regex (payment|pay|checkout|purchase|place order|... |billing). The order-update action's schema or description very likely matched on a word such as billing (it has a billing_address field), while "refund" is not in the list at all.
Suggested fix
Classify on what the action does, not on words found anywhere in its schema. At least match against the action's name and the arguments actually sent, not field names that were left empty.
Add refunds to the money rule (refund, create_refund), since they move money.
Consider letting an administrator mark a specific action as not money-moving (an allow rule that the safety layer respects), with the decision recorded in the audit log.
Hit a similar false-positive / false-negative pattern when gating device tools: matching against schema text (field names like billing_address) is too broad, while omitting verbs that actually move money (refund) is too narrow.
A pattern that held up for us on a local agent node:
Classify on the action id / tool name first (stable allow/deny table), then on the arguments actually sent (non-empty values only)—never on unused schema fields.
Keep money-moving as an explicit denylist of action ids (*_CREATE_REFUND, *_CAPTURE_PAYMENT, …) rather than a keyword regex over the whole description/schema.
Bind any allow-once approval to (action_id, args_hash, policy_version) so a later call with different args cannot reuse the token.
That still leaves room for an admin override that marks a specific action as not money-moving, with the decision written to the audit log—exactly the third bullet in the suggested fix. Happy to dig into a concrete Shopify action pair if useful.
Activity
linear-code commentedon Oct 29, 2026
FOR-353
LofiSu commentedon Oct 30, 2026
Hit a similar false-positive / false-negative pattern when gating device tools: matching against schema text (field names like
billing_address) is too broad, while omitting verbs that actually move money (refund) is too narrow.A pattern that held up for us on a local agent node:
*_CREATE_REFUND,*_CAPTURE_PAYMENT, …) rather than a keyword regex over the whole description/schema.(action_id, args_hash, policy_version)so a later call with different args cannot reuse the token.That still leaves room for an admin override that marks a specific action as not money-moving, with the decision written to the audit log—exactly the third bullet in the suggested fix. Happy to dig into a concrete Shopify action pair if useful.
fix(approvals): stop empty fields tripping the safety rules (#930)