@wowok/agent-mcp 3.1.3 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/config-audit.spec.d.ts +1 -0
- package/dist/config/config-audit.spec.js +1 -0
- package/dist/config/exposure.d.ts +108 -0
- package/dist/config/exposure.js +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +1 -1
- package/dist/config/judgment.d.ts +1228 -0
- package/dist/config/judgment.js +1 -0
- package/dist/config/judgment.spec.d.ts +1 -0
- package/dist/config/judgment.spec.js +1 -0
- package/dist/config/rule-engine.d.ts +299 -0
- package/dist/config/rule-engine.js +1 -0
- package/dist/config/rule-engine.spec.d.ts +1 -0
- package/dist/config/rule-engine.spec.js +1 -0
- package/dist/config/severity.d.ts +7 -0
- package/dist/config/severity.js +1 -0
- package/dist/customer/order-monitor.d.ts +3 -1
- package/dist/customer/order-monitor.js +1 -1
- package/dist/evaluation/acceptance.d.ts +1 -0
- package/dist/evaluation/acceptance.js +1 -1
- package/dist/evaluation/arbitration-game.js +1 -1
- package/dist/evaluation/builtins/demand-match.js +1 -1
- package/dist/evaluation/builtins/graph-service.js +1 -1
- package/dist/evaluation/builtins/graph-service.spec.js +1 -1
- package/dist/evaluation/engine.js +1 -1
- package/dist/evaluation/game-strategy.d.ts +2 -2
- package/dist/evaluation/game-strategy.js +1 -1
- package/dist/evaluation/match-operation.d.ts +2 -2
- package/dist/evaluation/match-operation.js +1 -1
- package/dist/evaluation/standards.d.ts +3 -25
- package/dist/evaluation/standards.js +1 -1
- package/dist/evaluation/types.d.ts +2 -1
- package/dist/experience/realtime-feedback.js +1 -1
- package/dist/extensions/business-modules.js +1 -1
- package/dist/extensions/custom-registry-file.js +1 -1
- package/dist/extensions/industry-audit.spec.d.ts +1 -0
- package/dist/extensions/industry-audit.spec.js +1 -0
- package/dist/extensions/industry-layers.d.ts +8 -0
- package/dist/extensions/industry-layers.js +1 -1
- package/dist/extensions/industry-pack.d.ts +2 -0
- package/dist/extensions/industry-pack.js +1 -1
- package/dist/extensions/mode-evaluator.js +1 -1
- package/dist/extensions/modes.js +1 -1
- package/dist/graph/onchain/analyze.d.ts +3 -1
- package/dist/graph/onchain/analyze.js +1 -1
- package/dist/graph/onchain/analyze.spec.js +1 -1
- package/dist/graph/onchain/edge-schema.d.ts +1 -0
- package/dist/graph/onchain/edge-schema.js +1 -1
- package/dist/graph/onchain/expand.js +1 -1
- package/dist/graph/onchain/exploration.d.ts +28 -0
- package/dist/graph/onchain/exploration.js +1 -0
- package/dist/graph/onchain/exploration.spec.d.ts +1 -0
- package/dist/graph/onchain/exploration.spec.js +1 -0
- package/dist/graph/onchain/exposure.d.ts +18 -0
- package/dist/graph/onchain/exposure.js +1 -0
- package/dist/graph/onchain/exposure.spec.d.ts +1 -0
- package/dist/graph/onchain/exposure.spec.js +1 -0
- package/dist/graph/onchain/graph-policy.spec.d.ts +1 -0
- package/dist/graph/onchain/graph-policy.spec.js +1 -0
- package/dist/graph/onchain/index.d.ts +6 -0
- package/dist/graph/onchain/index.js +1 -1
- package/dist/graph/onchain/interest.js +1 -1
- package/dist/graph/onchain/interest.spec.js +1 -1
- package/dist/graph/onchain/names.js +1 -1
- package/dist/graph/onchain/names.spec.js +1 -1
- package/dist/graph/onchain/policy.d.ts +8 -0
- package/dist/graph/onchain/policy.js +1 -0
- package/dist/graph/onchain/proposal-graph.js +1 -1
- package/dist/graph/onchain/proposal-graph.spec.js +1 -1
- package/dist/graph/onchain/synthesis.d.ts +20 -0
- package/dist/graph/onchain/synthesis.js +1 -0
- package/dist/graph/onchain/synthesis.spec.d.ts +1 -0
- package/dist/graph/onchain/synthesis.spec.js +1 -0
- package/dist/graph/onchain/types.d.ts +11 -1
- package/dist/keeper/keeper.spec.js +1 -1
- package/dist/knowledge/alloc-audit-policy.spec.d.ts +1 -0
- package/dist/knowledge/alloc-audit-policy.spec.js +1 -0
- package/dist/knowledge/allocation-ledger.js +1 -1
- package/dist/knowledge/allocation-puzzle.d.ts +1 -1
- package/dist/knowledge/allocation-puzzle.js +1 -1
- package/dist/knowledge/allocation-risk.d.ts +4 -1
- package/dist/knowledge/allocation-risk.js +1 -1
- package/dist/knowledge/allocation-templates.js +1 -1
- package/dist/knowledge/arb-risk.d.ts +6 -5
- package/dist/knowledge/arb-risk.js +1 -1
- package/dist/knowledge/arbitration-ledger.d.ts +4 -4
- package/dist/knowledge/arbitration-ledger.js +1 -1
- package/dist/knowledge/arbitration-puzzle.d.ts +1 -1
- package/dist/knowledge/arbitration-puzzle.js +1 -1
- package/dist/knowledge/arbitration-risk.d.ts +4 -1
- package/dist/knowledge/arbitration-risk.js +1 -1
- package/dist/knowledge/arbitration-templates.js +1 -1
- package/dist/knowledge/baselines/judgment-baselines.json +289 -0
- package/dist/knowledge/baselines/risk-baselines.spec.js +1 -1
- package/dist/knowledge/baselines/rules/alloc_audit.json +290 -0
- package/dist/knowledge/baselines/rules/allocation.json +492 -0
- package/dist/knowledge/baselines/rules/arb.json +155 -0
- package/dist/knowledge/baselines/rules/arbitration.json +366 -0
- package/dist/knowledge/baselines/rules/bridge.json +197 -0
- package/dist/knowledge/baselines/rules/contact.json +152 -0
- package/dist/knowledge/baselines/rules/demand.json +158 -0
- package/dist/knowledge/baselines/rules/graph.json +453 -0
- package/dist/knowledge/baselines/rules/guard.json +981 -0
- package/dist/knowledge/baselines/rules/machine.json +706 -0
- package/dist/knowledge/baselines/rules/order.json +549 -0
- package/dist/knowledge/baselines/rules/payment.json +205 -0
- package/dist/knowledge/baselines/rules/permission.json +330 -0
- package/dist/knowledge/baselines/rules/personal.json +139 -0
- package/dist/knowledge/baselines/rules/progress.json +346 -0
- package/dist/knowledge/baselines/rules/proof.json +158 -0
- package/dist/knowledge/baselines/rules/registrar.json +159 -0
- package/dist/knowledge/baselines/rules/repository.json +244 -0
- package/dist/knowledge/baselines/rules/resource.json +117 -0
- package/dist/knowledge/baselines/rules/reward.json +471 -0
- package/dist/knowledge/baselines/rules/service.json +595 -0
- package/dist/knowledge/baselines/rules/treasury.json +440 -0
- package/dist/knowledge/baselines/rules/util.json +101 -0
- package/dist/knowledge/bridge-risk.d.ts +6 -5
- package/dist/knowledge/bridge-risk.js +1 -1
- package/dist/knowledge/builtin-templates.d.ts +26 -0
- package/dist/knowledge/builtin-templates.js +1 -0
- package/dist/knowledge/contact-risk.d.ts +6 -5
- package/dist/knowledge/contact-risk.js +1 -1
- package/dist/knowledge/demand-risk.d.ts +6 -5
- package/dist/knowledge/demand-risk.js +1 -1
- package/dist/knowledge/event-semantics.js +1 -1
- package/dist/knowledge/facts-sync.spec.d.ts +1 -0
- package/dist/knowledge/facts-sync.spec.js +1 -0
- package/dist/knowledge/getting-started.js +1 -1
- package/dist/knowledge/guard-design-patterns.js +1 -1
- package/dist/knowledge/guard-field-cognition.d.ts +1 -1
- package/dist/knowledge/guard-field-cognition.js +1 -1
- package/dist/knowledge/guard-ledger.js +1 -1
- package/dist/knowledge/guard-risk.d.ts +4 -1
- package/dist/knowledge/guard-risk.js +1 -1
- package/dist/knowledge/guard-templates.js +1 -1
- package/dist/knowledge/guard-translation.js +1 -1
- package/dist/knowledge/index.d.ts +10 -2
- package/dist/knowledge/index.js +1 -1
- package/dist/knowledge/industry-registry.js +1 -1
- package/dist/knowledge/industry-strategy.js +1 -1
- package/dist/knowledge/jsonrpc-enum.js +1 -1
- package/dist/knowledge/machine-ledger.js +1 -1
- package/dist/knowledge/machine-risk.d.ts +4 -1
- package/dist/knowledge/machine-risk.js +1 -1
- package/dist/knowledge/machine-templates.js +1 -1
- package/dist/knowledge/machine-translation.js +1 -1
- package/dist/knowledge/migration-preflight.js +1 -1
- package/dist/knowledge/operation-dictionary.js +1 -1
- package/dist/knowledge/order-ledger.js +1 -1
- package/dist/knowledge/order-puzzle.d.ts +3 -3
- package/dist/knowledge/order-puzzle.js +1 -1
- package/dist/knowledge/order-risk.d.ts +6 -3
- package/dist/knowledge/order-risk.js +1 -1
- package/dist/knowledge/order-templates.js +1 -1
- package/dist/knowledge/passport-ledger.js +1 -1
- package/dist/knowledge/passport-templates.js +1 -1
- package/dist/knowledge/payment-risk.d.ts +8 -6
- package/dist/knowledge/payment-risk.js +1 -1
- package/dist/knowledge/payment-tracker.js +1 -1
- package/dist/knowledge/permission-ledger.js +1 -1
- package/dist/knowledge/permission-puzzle.d.ts +12 -12
- package/dist/knowledge/permission-puzzle.js +1 -1
- package/dist/knowledge/permission-risk.d.ts +4 -7
- package/dist/knowledge/permission-risk.js +1 -1
- package/dist/knowledge/permission-templates.js +1 -1
- package/dist/knowledge/personal-risk.d.ts +6 -5
- package/dist/knowledge/personal-risk.js +1 -1
- package/dist/knowledge/progress-ledger.js +1 -1
- package/dist/knowledge/progress-puzzle.d.ts +2 -2
- package/dist/knowledge/progress-puzzle.js +1 -1
- package/dist/knowledge/progress-risk.d.ts +4 -1
- package/dist/knowledge/progress-risk.js +1 -1
- package/dist/knowledge/progress-templates.js +1 -1
- package/dist/knowledge/proof-risk.d.ts +6 -5
- package/dist/knowledge/proof-risk.js +1 -1
- package/dist/knowledge/puzzle-projections.js +1 -1
- package/dist/knowledge/recipient-constraint.d.ts +20 -1
- package/dist/knowledge/recipient-constraint.js +1 -1
- package/dist/knowledge/registrar-risk.d.ts +6 -5
- package/dist/knowledge/registrar-risk.js +1 -1
- package/dist/knowledge/repository-risk.d.ts +7 -6
- package/dist/knowledge/repository-risk.js +1 -1
- package/dist/knowledge/resource-risk.d.ts +6 -5
- package/dist/knowledge/resource-risk.js +1 -1
- package/dist/knowledge/reward-ledger.d.ts +1 -1
- package/dist/knowledge/reward-ledger.js +1 -1
- package/dist/knowledge/reward-puzzle.d.ts +2 -2
- package/dist/knowledge/reward-puzzle.js +1 -1
- package/dist/knowledge/reward-risk.d.ts +4 -1
- package/dist/knowledge/reward-risk.js +1 -1
- package/dist/knowledge/rule-node-analyzers.spec.js +1 -1
- package/dist/knowledge/rule-outcome.js +1 -1
- package/dist/knowledge/scenario-modes.d.ts +2 -2
- package/dist/knowledge/scenario-modes.js +1 -1
- package/dist/knowledge/scenario-topology.js +1 -1
- package/dist/knowledge/service-allocator-audit-node.js +1 -1
- package/dist/knowledge/service-ledger.js +1 -1
- package/dist/knowledge/service-puzzle.d.ts +2 -2
- package/dist/knowledge/service-puzzle.js +1 -1
- package/dist/knowledge/service-risk-node.js +1 -1
- package/dist/knowledge/service-risk.d.ts +4 -1
- package/dist/knowledge/service-risk.js +1 -1
- package/dist/knowledge/service-templates.js +1 -1
- package/dist/knowledge/strategy-manuals.d.ts +1 -1
- package/dist/knowledge/strategy-manuals.js +1 -1
- package/dist/knowledge/template-loader.d.ts +84 -0
- package/dist/knowledge/template-loader.js +1 -0
- package/dist/knowledge/template-loader.spec.d.ts +1 -0
- package/dist/knowledge/template-loader.spec.js +1 -0
- package/dist/knowledge/template-registry.js +1 -1
- package/dist/knowledge/template-scanner.d.ts +17 -0
- package/dist/knowledge/template-scanner.js +1 -0
- package/dist/knowledge/template-scanner.spec.d.ts +1 -0
- package/dist/knowledge/template-scanner.spec.js +1 -0
- package/dist/knowledge/tools-reference.js +1 -1
- package/dist/knowledge/treasury-ledger.d.ts +1 -1
- package/dist/knowledge/treasury-ledger.js +1 -1
- package/dist/knowledge/treasury-puzzle.d.ts +3 -3
- package/dist/knowledge/treasury-puzzle.js +1 -1
- package/dist/knowledge/treasury-risk.d.ts +4 -1
- package/dist/knowledge/treasury-risk.js +1 -1
- package/dist/knowledge/treasury-templates.js +1 -1
- package/dist/knowledge/util-risk.d.ts +6 -5
- package/dist/knowledge/util-risk.js +1 -1
- package/dist/knowledge/workflow-guidance.d.ts +4 -0
- package/dist/knowledge/workflow-guidance.js +1 -1
- package/dist/knowledge/workspace-lists.js +1 -1
- package/dist/monitor/MonitorLoop.js +1 -1
- package/dist/participation/arbitrator-interest.js +1 -1
- package/dist/participation/radar-core.js +1 -1
- package/dist/persona/analyzer.js +1 -1
- package/dist/persona/index.js +1 -1
- package/dist/persona/model.js +1 -1
- package/dist/persona/persona-audit.spec.d.ts +1 -0
- package/dist/persona/persona-audit.spec.js +1 -0
- package/dist/persona/types.d.ts +2 -0
- package/dist/playbooks/service-build/business-puzzle.js +1 -1
- package/dist/playbooks/service-build/facet-money.d.ts +11 -0
- package/dist/playbooks/service-build/facet-money.js +1 -1
- package/dist/playbooks/service-build/machine-panorama.d.ts +17 -0
- package/dist/playbooks/service-build/machine-panorama.js +1 -1
- package/dist/playbooks/service-build/merchant-guide.d.ts +2 -2
- package/dist/playbooks/service-build/migration-planner.d.ts +43 -0
- package/dist/playbooks/service-build/migration-planner.js +1 -0
- package/dist/playbooks/service-build/object-panorama.d.ts +42 -1
- package/dist/playbooks/service-build/object-panorama.js +1 -1
- package/dist/playbooks/service-build/participation-radar.js +1 -1
- package/dist/playbooks/service-build/pipeline-actions.d.ts +1 -1
- package/dist/playbooks/service-build/reverse-mapping.d.ts +1 -0
- package/dist/playbooks/service-build/reverse-mapping.js +1 -1
- package/dist/playbooks/service-build/risk-aggregator.d.ts +2 -1
- package/dist/playbooks/service-build/risk-aggregator.js +1 -1
- package/dist/playbooks/service-build/semantic-graph.js +1 -1
- package/dist/playbooks/service-build/service-panorama.d.ts +53 -1
- package/dist/playbooks/service-build/service-panorama.js +1 -1
- package/dist/playbooks/service-build/topology-evaluation.spec.js +1 -1
- package/dist/playbooks/service-build/topology-query.js +1 -1
- package/dist/playbooks/service-build/workflow-design-assessment.d.ts +2 -2
- package/dist/playbooks/service-build/workflow-design-assessment.js +1 -1
- package/dist/relationship/registry.js +1 -1
- package/dist/review/machine.js +1 -1
- package/dist/review/order.js +1 -1
- package/dist/review/service.js +1 -1
- package/dist/review/types.d.ts +7 -0
- package/dist/safety/confirm-gate.js +1 -1
- package/dist/schema/benchmark-migration/index.d.ts +207 -0
- package/dist/schema/benchmark-migration/index.js +1 -0
- package/dist/schema/call/allocation.d.ts +1 -1
- package/dist/schema/call/allocation.js +1 -1
- package/dist/schema/call/arbitration.d.ts +1 -1
- package/dist/schema/call/arbitration.js +1 -1
- package/dist/schema/call/base.d.ts +5 -5
- package/dist/schema/call/base.js +1 -1
- package/dist/schema/call/contact.d.ts +1 -1
- package/dist/schema/call/demand.d.ts +1 -1
- package/dist/schema/call/guard.d.ts +3 -3
- package/dist/schema/call/machine.d.ts +5 -5
- package/dist/schema/call/order.d.ts +3 -3
- package/dist/schema/call/payment.js +1 -1
- package/dist/schema/call/permission-handler.d.ts +1 -1
- package/dist/schema/call/permission-handler.js +1 -1
- package/dist/schema/call/permission.d.ts +16 -16
- package/dist/schema/call/permission.js +1 -1
- package/dist/schema/call/personal.d.ts +8 -8
- package/dist/schema/call/personal.js +1 -1
- package/dist/schema/call/progress.d.ts +3 -3
- package/dist/schema/call/repository.d.ts +11 -11
- package/dist/schema/call/repository.js +1 -1
- package/dist/schema/call/reward.d.ts +1 -1
- package/dist/schema/call/semantic.js +1 -1
- package/dist/schema/call/service.d.ts +7 -7
- package/dist/schema/call/service.js +1 -1
- package/dist/schema/call/treasury.d.ts +1 -1
- package/dist/schema/common/index.d.ts +6 -6
- package/dist/schema/common/index.js +1 -1
- package/dist/schema/config/index.d.ts +50 -1
- package/dist/schema/config/index.js +1 -1
- package/dist/schema/evaluation/index.d.ts +27 -11
- package/dist/schema/evaluation/index.js +1 -1
- package/dist/schema/goal/index.d.ts +5 -5
- package/dist/schema/goal/planning.d.ts +15 -15
- package/dist/schema/goal/planning.js +1 -1
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -1
- package/dist/schema/interaction/index.d.ts +1 -1
- package/dist/schema/local/index.js +1 -1
- package/dist/schema/messenger/index.d.ts +26 -26
- package/dist/schema/operations.d.ts +33 -33
- package/dist/schema/operations.js +1 -1
- package/dist/schema/persona/index.d.ts +4708 -0
- package/dist/schema/persona/index.js +1 -1
- package/dist/schema/query/bi.d.ts +232 -25
- package/dist/schema/query/bi.js +1 -1
- package/dist/schema/query/index.d.ts +35 -35
- package/dist/schema/query/index.js +1 -1
- package/dist/schema/schema-version.js +1 -1
- package/dist/schema/workflow/index.d.ts +1 -1
- package/dist/schema-query-impl/index.d.ts +9 -0
- package/dist/schema-query-impl/index.js +1 -1
- package/dist/schemas/benchmark_migration_operation.output.json +793 -0
- package/dist/schemas/benchmark_migration_operation.schema.json +83 -0
- package/dist/schemas/bridge_operation.schema.json +5 -5
- package/dist/schemas/config_operation.output.json +252 -0
- package/dist/schemas/config_operation.schema.json +21 -1
- package/dist/schemas/evaluation_operation.output.json +22 -10
- package/dist/schemas/goal_operation.schema.json +8 -8
- package/dist/schemas/guard2file.schema.json +1 -1
- package/dist/schemas/index.json +7 -1
- package/dist/schemas/machineNode2file.schema.json +1 -1
- package/dist/schemas/messenger_operation.schema.json +24 -12
- package/dist/schemas/onchain_events.output.json +1 -1
- package/dist/schemas/onchain_operations.output.json +4 -2
- package/dist/schemas/onchain_operations.schema.json +189 -139
- package/dist/schemas/onchain_operations_allocation.schema.json +13 -11
- package/dist/schemas/onchain_operations_arbitration.schema.json +10 -8
- package/dist/schemas/onchain_operations_contact.schema.json +7 -5
- package/dist/schemas/onchain_operations_demand.schema.json +7 -5
- package/dist/schemas/onchain_operations_gen_passport.schema.json +5 -3
- package/dist/schemas/onchain_operations_gen_proof.schema.json +1 -1
- package/dist/schemas/onchain_operations_guard.schema.json +5 -3
- package/dist/schemas/onchain_operations_machine.schema.json +22 -18
- package/dist/schemas/onchain_operations_order.schema.json +11 -7
- package/dist/schemas/onchain_operations_payment.schema.json +3 -3
- package/dist/schemas/onchain_operations_permission.schema.json +19 -11
- package/dist/schemas/onchain_operations_personal.schema.json +16 -10
- package/dist/schemas/onchain_operations_progress.schema.json +11 -7
- package/dist/schemas/onchain_operations_proof.schema.json +5 -3
- package/dist/schemas/onchain_operations_repository.schema.json +12 -8
- package/dist/schemas/onchain_operations_reward.schema.json +11 -9
- package/dist/schemas/onchain_operations_service.schema.json +28 -22
- package/dist/schemas/onchain_operations_treasury.schema.json +11 -9
- package/dist/schemas/onchain_table_data.output.json +27 -17
- package/dist/schemas/persona_operation.output.json +15875 -1
- package/dist/schemas/persona_operation.schema.json +3056 -478
- package/dist/schemas/query_toolkit.output.json +343 -63
- package/dist/schemas/query_toolkit.schema.json +1 -1
- package/dist/schemas/workflow_operation.schema.json +4 -2
- package/dist/strategy/scorecard.js +1 -1
- package/dist/tools/handlers/benchmark-migration.d.ts +2 -0
- package/dist/tools/handlers/benchmark-migration.js +1 -0
- package/dist/tools/handlers/config.js +1 -1
- package/dist/tools/handlers/industry-pack.js +1 -1
- package/dist/tools/handlers/onchain.js +1 -1
- package/dist/tools/handlers/query.js +1 -1
- package/dist/tools/handlers/schema-query.js +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/move-fn-index.gen.d.ts +3 -0
- package/dist/tools/move-fn-index.gen.js +1 -0
- package/dist/tools/registry/business.js +1 -1
- package/dist/tools/registry/config.js +1 -1
- package/dist/tools/registry/evaluation.js +1 -1
- package/dist/tools/registry/onchain.js +1 -1
- package/dist/tools/sanitize-output.d.ts +3 -0
- package/dist/tools/sanitize-output.js +1 -0
- package/dist/tools/sanitize-output.spec.d.ts +1 -0
- package/dist/tools/sanitize-output.spec.js +1 -0
- package/package.json +9 -4
- package/dist/knowledge/baselines/evaluation-baselines.json +0 -79
|
@@ -0,0 +1,981 @@
|
|
|
1
|
+
{
|
|
2
|
+
"comment": "Guard rule pack (R-C/R-X) — declarative form of the retired in-code Guard risk rules (the guard condition-tree lint pack: 32 rules over the serialized root, table classification and the scene ledger). Facts are produced by the kernel extractor (guard-risk.ts, bound to the GUARDQUERY invariant catalog, the witness chain table and the per-scene reentrancy specs); rules only reference fact names. Levels/wording can be retuned per rule and rules can be disabled (enabled=false, trace left) via the judgment document — factory rules can never be deleted or invented here.",
|
|
3
|
+
"facts": {
|
|
4
|
+
"has_signer_check": "KERNEL — the serialized root contains a context(Signer) check.",
|
|
5
|
+
"has_clock_check": "KERNEL — the serialized root contains a context(Clock) node.",
|
|
6
|
+
"has_guard_self_ref": "KERNEL — the serialized root contains a context(Guard) self-reference.",
|
|
7
|
+
"has_witness": "KERNEL — the serialized root contains a convert_witness field.",
|
|
8
|
+
"queries_repository": "KERNEL — the serialized root mentions repository (Repository data source).",
|
|
9
|
+
"queries_progress": "KERNEL — the serialized root mentions progress (Progress data source).",
|
|
10
|
+
"root_has_query": "KERNEL — the serialized root contains a \"query\" node marker.",
|
|
11
|
+
"root_has_clock_token": "KERNEL — the lowercased serialized root contains the clock token.",
|
|
12
|
+
"root_has_calc_number_add": "KERNEL — the serialized root uses calc_number_add.",
|
|
13
|
+
"root_has_logic_string_contains": "KERNEL — the serialized root uses logic_string_contains.",
|
|
14
|
+
"root_has_logic_string_nocase": "KERNEL — the serialized root uses the logic_string_nocase variant.",
|
|
15
|
+
"root_has_logic_as_u256_greater_or_equal": "KERNEL — the serialized root uses logic_as_u256_greater_or_equal.",
|
|
16
|
+
"root_has_logic_as_u256_greater": "KERNEL — the serialized root uses logic_as_u256_greater (substring semantics: also matches the greater_or_equal form, as the retired code did).",
|
|
17
|
+
"root_has_logic_equal": "KERNEL — the serialized root contains a logic_equal node.",
|
|
18
|
+
"root_has_logic_not_equal": "KERNEL — the serialized root contains a logic_not_equal node.",
|
|
19
|
+
"root_is_identifier": "KERNEL — the root node itself is an identifier node.",
|
|
20
|
+
"root_identifier_is_submission": "KERNEL — when the root is an identifier, the referenced table entry has b_submission=true (false when the entry is missing or constant).",
|
|
21
|
+
"root_query_ids_csv": "KERNEL — all GUARDQUERY ids referenced in the root (numeric ids and resolved names), comma-space joined.",
|
|
22
|
+
"root_has_progress_current_query": "KERNEL — the root queries progress.current (query id 1253).",
|
|
23
|
+
"logic_and_count": "KERNEL — number of logic_and markers in the serialized root.",
|
|
24
|
+
"const_addr_list": "KERNEL — constant Address table entries (b_submission=false, value set) rendered as '#id=value', comma joined.",
|
|
25
|
+
"const_addr_count": "KERNEL — number of constant Address table entries (b_submission=false, value set).",
|
|
26
|
+
"sys_addr_list": "KERNEL — system-address table entries (0xaab/0xaaa) rendered as '#id=value(name)', comma joined.",
|
|
27
|
+
"sys_addr_wrong": "KERNEL — a system-address entry's name annotation contradicts the address (0xaab not named *registrar* / 0xaaa not named *linker*).",
|
|
28
|
+
"witness_multihop_codes": "KERNEL — multi-hop witness codes (106/107/108) present in the root.",
|
|
29
|
+
"witness_multihop_csv": "KERNEL — witness_multihop_codes comma-space joined.",
|
|
30
|
+
"witness_multihop_names_block": "KERNEL — one ' - <code>: <chain name>' line per multi-hop witness code, newline joined.",
|
|
31
|
+
"rc2_02_issue_count": "KERNEL — witness-source table annotation issues found (hard mismatches + missing annotations).",
|
|
32
|
+
"rc2_02_has_hard_mismatch": "KERNEL — at least one explicit object_type contradiction with the witness derivation chain.",
|
|
33
|
+
"rc2_02_evidence_lines": "KERNEL — the issue list rendered as ' - <issue>' lines, newline joined.",
|
|
34
|
+
"rc2_02_evidence_csv": "KERNEL — the issue list joined with '; '.",
|
|
35
|
+
"rc2_04_queries_repo": "KERNEL — the root queries repository data (translation-relevant).",
|
|
36
|
+
"rc2_04_queries_progress_history": "KERNEL — the root queries progress history (translation-relevant).",
|
|
37
|
+
"rc2_04_has_conversion": "KERNEL — the root already uses a type-conversion node (convert_number_address / convert_address_number / convert_u256 / convert_string).",
|
|
38
|
+
"rc2_04_conversion_note": "KERNEL — final description tail for the conversion-present vs conversion-missing branches.",
|
|
39
|
+
"rc2_04_conversion_evidence": "KERNEL — final evidence for the conversion-present vs conversion-missing branches.",
|
|
40
|
+
"has_submission": "KERNEL — the table has at least one b_submission=true entry.",
|
|
41
|
+
"scene_present": "KERNEL — a binding scene was supplied.",
|
|
42
|
+
"scene_id": "KERNEL — the binding scene id (e.g. service_order_allocators_guard).",
|
|
43
|
+
"scene_host_object": "KERNEL — the binding scene host object type (Service/Machine/...).",
|
|
44
|
+
"scene_binding_field": "KERNEL — the binding scene binding field (buy_guard/order_allocators/...).",
|
|
45
|
+
"scene_mutable_after_publish": "KERNEL — whether the scene binding can be modified after the host object is published.",
|
|
46
|
+
"rc3_01_sharing_exempt": "KERNEL — allocators scene with Entity/GuardIdentifier-only sharing (Signer binding advice does not apply; R-C3-06 owns the semantics).",
|
|
47
|
+
"rc3_02_numeric_count": "KERNEL — submitted numeric table entries (U8..U256) in the voting_guard scene.",
|
|
48
|
+
"rc3_02_numeric_list": "KERNEL — submitted numeric entries rendered as '#id(TYPE)', comma joined.",
|
|
49
|
+
"rc3_03_submitted_addr_count": "KERNEL — submitted Address table entries (b_submission=true, value_type=Address).",
|
|
50
|
+
"rc3_03_no_type_count": "KERNEL — submitted Address entries missing the object_type annotation.",
|
|
51
|
+
"rc3_03_evidence": "KERNEL — final evidence listing the missing-object_type or annotated entries.",
|
|
52
|
+
"rc3_05_applies": "KERNEL — a project-relevant object (Order/Progress/Arb) is submitted in an affected scene without a project-binding query (1563/1560/1250/1402/1401) in the root.",
|
|
53
|
+
"rc3_05_critical": "KERNEL — the scene belongs to the critical set (machine_forward_guard / service_order_allocators_guard).",
|
|
54
|
+
"rc3_05_unbound_csv": "KERNEL — unbound project-relevant submission entries rendered '#id(Order|Progress|Arb|inferred …)', comma joined.",
|
|
55
|
+
"rc3_05_scene_label": "KERNEL — scene label for the evidence ('unknown scene (conservative flag)' when absent).",
|
|
56
|
+
"rc3_06_applies": "KERNEL — allocators scene, Guard without Signer binding, and sharing is not provably Entity/GuardIdentifier-only.",
|
|
57
|
+
"rc3_06_signer_sharing": "KERNEL — sharing.who=Signer confirmed via the sharing_recipients hint.",
|
|
58
|
+
"rc3_06_recipients_label": "KERNEL — rendered sharing recipients hint ('[Signer]' or '(not provided — conservative flag)').",
|
|
59
|
+
"rc3_06_title_suffix": "KERNEL — final title suffix for the confirmed vs conservative branches.",
|
|
60
|
+
"rc3_06_level_rationale": "KERNEL — final level rationale for the evidence line.",
|
|
61
|
+
"rc4_01_comparison_detail": "KERNEL — detected comparison operators rendered 'logic_equal(==) logic_not_equal(!=)' (blank when absent).",
|
|
62
|
+
"rc4_01_comparison_ops": "KERNEL — detected comparison operators rendered '== !=' (blank when absent).",
|
|
63
|
+
"rc4_02_has_greater_or_equal": "KERNEL — the root uses logic_as_u256_greater_or_equal (Clock boundary form).",
|
|
64
|
+
"rc4_02_has_greater": "KERNEL — the root uses logic_as_u256_greater (substring semantics).",
|
|
65
|
+
"rc4_02_comparison_ops": "KERNEL — detected comparison operators rendered '>= >' (blank when absent).",
|
|
66
|
+
"rc4_04_detected": "KERNEL — Level 1 strict single-identity Signer binding detected (logic_equal[context(Signer), identifier[N]] on a fixed Address constant, not wrapped in logic_or).",
|
|
67
|
+
"rc4_04_entry_identifier": "KERNEL — table identifier of the detected Level 1 strict-binding entry.",
|
|
68
|
+
"rc4_04_entry_value": "KERNEL — fixed Address value of the detected entry.",
|
|
69
|
+
"rc4_04_entry_detail": "KERNEL — entry constraint detail rendered 'b_submission=false, value=\"…\"(, name=\"…\")?'.",
|
|
70
|
+
"rx1_01_trigger": "KERNEL — greater_or_equal + clock + calc_number_add + query present and at least one root query lacks a non-zero invariant.",
|
|
71
|
+
"rx1_01_evidence": "KERNEL — final evidence listing queries without a non-zero invariant (or the static fallback).",
|
|
72
|
+
"rx1_02_trigger": "KERNEL — greater + query present and at least one root query lacks a non-zero invariant.",
|
|
73
|
+
"rx1_02_evidence": "KERNEL — final evidence listing queries without a non-zero invariant (or the static fallback).",
|
|
74
|
+
"rely_guards_count": "KERNEL — number of external Guards in the rely configuration.",
|
|
75
|
+
"rely_is_or": "KERNEL — the rely combination is OR (vs AND).",
|
|
76
|
+
"rely_logic": "KERNEL — final 'OR'/'AND' label of the rely combination.",
|
|
77
|
+
"rx1_11_self_rep_false": "KERNEL — this Guard queries repository.data with a submitted Repository address (own rep=false).",
|
|
78
|
+
"rx1_11_warning_tail": "KERNEL — final description tail appended when own rep=false (empty otherwise).",
|
|
79
|
+
"rx1_11_evidence": "KERNEL — final evidence for the own rep=false vs to-be-confirmed branches.",
|
|
80
|
+
"rx1_12_vague_count": "KERNEL — submitted entries with vague name descriptions (< 10 chars, bare identifiers, or empty).",
|
|
81
|
+
"rx1_12_vague_csv": "KERNEL — vague entries rendered 'identifier=N, name=\"…\"', '; ' joined.",
|
|
82
|
+
"rx1_13_detected": "KERNEL — a table Address constant's object_type equals the scene host object (circular reference pattern).",
|
|
83
|
+
"rx1_13_identifier": "KERNEL — identifier of the circular-reference table entry.",
|
|
84
|
+
"reentry_applicable": "KERNEL — the scene has a reentrancy spec (ALLOWED scenes stay silent).",
|
|
85
|
+
"reentry_state": "KERNEL — anti-reentrancy protection state: 'protected' / 'pseudo' / 'absent'.",
|
|
86
|
+
"reentry_scene_id": "KERNEL — reentrancy scene id from the spec table.",
|
|
87
|
+
"reentry_found_primitive": "KERNEL — GUARDQUERY name of the anti-reentrancy primitive found in the root.",
|
|
88
|
+
"reentry_evidence": "KERNEL — final detection evidence of the reentrancy scan.",
|
|
89
|
+
"reentry_rationale": "KERNEL — per-scene reentrancy rationale (spec table, Move-verified).",
|
|
90
|
+
"reentry_mitigation": "KERNEL — per-scene reentrancy mitigation (spec table, Move-verified)."
|
|
91
|
+
},
|
|
92
|
+
"rules": [
|
|
93
|
+
{
|
|
94
|
+
"rule_id": "R-C1-01",
|
|
95
|
+
"dimension": "data_source_trust",
|
|
96
|
+
"trigger": "Guard table contains Address constants with b_submission=false; values may change after Guard rebuild",
|
|
97
|
+
"cases": [
|
|
98
|
+
{
|
|
99
|
+
"when": { "field": "const_addr_list", "op": "present" },
|
|
100
|
+
"level": "low",
|
|
101
|
+
"title": "Constant object addresses may be inconsistent after Guard rebuild",
|
|
102
|
+
"description": "Guard table contains ${const_addr_count} Address constants (b_submission=false).Guard is immutable, but if a future Guard rebuild is needed (e.g. to fix logic), the new Guard's table constant addresses may differ from the old version.Objects referencing the old Guard (Machine/Service, etc.) will not auto-update, leading to constant address inconsistency.",
|
|
103
|
+
"scenario": "Guard iteration: after rebuild, constant addresses change but references still point to the old Guard",
|
|
104
|
+
"mitigation": "1) After Guard rebuild, update all references (Machine forward guard, Service buy_guard, etc.);2) Use guard2file to export a backup and record constant-address-to-semantics mappings;3) Document constant-address changes in the migration notes",
|
|
105
|
+
"evidence": "Constant Address entries: ${const_addr_list}",
|
|
106
|
+
"stakeholders": ["provider"]
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"rule_id": "R-C1-02",
|
|
112
|
+
"dimension": "data_source_trust",
|
|
113
|
+
"trigger": "Guard table contains EntityRegistrar(0xaab) or EntityLinker(0xaaa) system address constants",
|
|
114
|
+
"cases": [
|
|
115
|
+
{
|
|
116
|
+
"when": { "all": [{ "field": "sys_addr_list", "op": "present" }, { "field": "sys_addr_wrong", "op": "eq", "value": true }] },
|
|
117
|
+
"level": "medium",
|
|
118
|
+
"title": "EntityRegistrar/EntityLinker system address name annotation suspected to be wrong",
|
|
119
|
+
"description": "EntityRegistrar (0xaab) and EntityLinker (0xaaa) are fixed WoWok protocol system addresses.Detected name annotation does not match the address (e.g. 0xaab not annotated as registrar), which may cause semantic misunderstanding.",
|
|
120
|
+
"scenario": "System address misuse: incorrect 0xaab/0xaaa name annotation causes query target confusion",
|
|
121
|
+
"mitigation": "1) Confirm 0xaab corresponds to EntityRegistrar (entity registrar);2) Confirm 0xaaa corresponds to EntityLinker (entity linker);3) The table entry name should clearly indicate the system address purpose",
|
|
122
|
+
"evidence": "System address entries: ${sys_addr_list}",
|
|
123
|
+
"stakeholders": ["provider"]
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"when": { "all": [{ "field": "sys_addr_list", "op": "present" }, { "field": "sys_addr_wrong", "op": "eq", "value": false }] },
|
|
127
|
+
"level": "low",
|
|
128
|
+
"title": "Guard uses EntityRegistrar/EntityLinker system address constants",
|
|
129
|
+
"description": "EntityRegistrar (0xaab) and EntityLinker (0xaaa) are fixed WoWok protocol system addresses.Address is correct, but ensure the name annotation is clear to avoid later maintenance confusion.",
|
|
130
|
+
"scenario": "System address misuse: incorrect 0xaab/0xaaa name annotation causes query target confusion",
|
|
131
|
+
"mitigation": "1) Confirm 0xaab corresponds to EntityRegistrar (entity registrar);2) Confirm 0xaaa corresponds to EntityLinker (entity linker);3) The table entry name should clearly indicate the system address purpose",
|
|
132
|
+
"evidence": "System address entries: ${sys_addr_list}",
|
|
133
|
+
"stakeholders": ["provider"]
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"rule_id": "R-C1-03",
|
|
139
|
+
"dimension": "data_source_trust",
|
|
140
|
+
"trigger": "Guard queries Repository data without verifying writer permissions",
|
|
141
|
+
"cases": [
|
|
142
|
+
{
|
|
143
|
+
"when": { "all": [{ "field": "queries_repository", "op": "eq", "value": true }, { "field": "has_signer_check", "op": "eq", "value": false }] },
|
|
144
|
+
"level": "high",
|
|
145
|
+
"title": "Repository data source does not verify writer permissions",
|
|
146
|
+
"description": "Guard queries Repository data but does not verify who has permission to write to that Repository.A malicious writer can manipulate Repository data to deceive the Guard. As a Type1 constant object, the Repository's address is immutable, but its internal data can be modified by authorized writers.",
|
|
147
|
+
"scenario": "Data source manipulation: attacker writes false data so Guard passes",
|
|
148
|
+
"mitigation": "1) Restrict writer permissions in the Repository write_guard;2) Add context(Signer) in the current Guard to verify writer identity;3) Use multi-point data source cross-validation",
|
|
149
|
+
"stakeholders": ["customer", "provider"]
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"rule_id": "R-C2-01",
|
|
155
|
+
"dimension": "data_source_trust",
|
|
156
|
+
"trigger": "Guard uses multi-hop witness (106/107/108: Arb→Progress/Machine/Service) to derive target object",
|
|
157
|
+
"cases": [
|
|
158
|
+
{
|
|
159
|
+
"when": { "field": "witness_multihop_codes", "op": "truthy" },
|
|
160
|
+
"level": "medium",
|
|
161
|
+
"title": "Multi-hop witness chain derivation may break",
|
|
162
|
+
"description": "Guard uses multi-hop witness [${witness_multihop_csv}] to derive target object.Multi-hop witness (e.g. Arb→Progress requires reading arb.order then order.progress) requires intermediate objects to exist and fields to be set.If an intermediate object does not exist (e.g. Arb's order field is empty) or the relationship chain breaks, witness derivation fails.In the WoWok protocol this usually returns empty or 0, potentially causing unexpected Guard behavior.\n${witness_multihop_names_block}",
|
|
163
|
+
"scenario": "Witness break: intermediate object missing causes derivation failure and unexpected Guard behavior",
|
|
164
|
+
"mitigation": "1) Confirm the Arb object's order field is properly set (Arb is bound to Order at creation);2) Add null checks for derived results in Guard logic;3) Prefer single-hop witness (100-105) to reduce derivation chain length;4) Test the edge case where Arb is not associated with an Order",
|
|
165
|
+
"evidence": "Multi-hop witness codes: ${witness_multihop_csv}",
|
|
166
|
+
"stakeholders": ["customer", "provider", "arbitrator"]
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"rule_id": "R-C2-02",
|
|
172
|
+
"dimension": "data_source_trust",
|
|
173
|
+
"trigger": "Guard uses witness but source object's object_type may not match the witness source type, or multi-hop chain has missing intermediate objects",
|
|
174
|
+
"cases": [
|
|
175
|
+
{
|
|
176
|
+
"when": { "all": [{ "field": "rc2_02_issue_count", "op": "gt", "value": 0 }, { "field": "rc2_02_has_hard_mismatch", "op": "eq", "value": true }] },
|
|
177
|
+
"level": "medium",
|
|
178
|
+
"title": "witness source object_type explicitly contradicts the witness derivation chain",
|
|
179
|
+
"description": "Guard uses witness derivation, but the source object's object_type in table is either inconsistent with the witness expected source type, or the annotation is missing (preventing validation), or the multi-hop chain lacks an intermediate object.\n${rc2_02_evidence_lines}\nNote: object_type is an auxiliary annotation field on table entries; it is not strictly validated at on-chain creation. However, wrong or missing annotations cause semantic misunderstanding and maintenance difficulty, and may indicate a deeper structural mismatch.",
|
|
180
|
+
"scenario": "Type annotation mismatch: witness source type annotation is wrong, causing semantic confusion",
|
|
181
|
+
"mitigation": "1) Set or fix the table entry's object_type field to match the witness source type;\n2) witness 100-102 source type is Order; 103 is Progress; 104-108 is Arb;\n3) For multi-hop witnesses (106-108), ensure the intermediate Order object is also in the table;\n4) Use wowok_buildin_info(info='guard instructions') to query the full witness definition",
|
|
182
|
+
"evidence": "${rc2_02_evidence_csv}",
|
|
183
|
+
"stakeholders": ["provider"]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"when": { "all": [{ "field": "rc2_02_issue_count", "op": "gt", "value": 0 }, { "field": "rc2_02_has_hard_mismatch", "op": "eq", "value": false }] },
|
|
187
|
+
"level": "low",
|
|
188
|
+
"title": "witness source object_type annotation missing or multi-hop chain incomplete",
|
|
189
|
+
"description": "Guard uses witness derivation, but the source object's object_type in table is either inconsistent with the witness expected source type, or the annotation is missing (preventing validation), or the multi-hop chain lacks an intermediate object.\n${rc2_02_evidence_lines}\nNote: object_type is an auxiliary annotation field on table entries; it is not strictly validated at on-chain creation. However, wrong or missing annotations cause semantic misunderstanding and maintenance difficulty, and may indicate a deeper structural mismatch.",
|
|
190
|
+
"scenario": "Type annotation missing: witness source type cannot be validated, raising maintenance risk",
|
|
191
|
+
"mitigation": "1) Set or fix the table entry's object_type field to match the witness source type;\n2) witness 100-102 source type is Order; 103 is Progress; 104-108 is Arb;\n3) For multi-hop witnesses (106-108), ensure the intermediate Order object is also in the table;\n4) Use wowok_buildin_info(info='guard instructions') to query the full witness definition",
|
|
192
|
+
"evidence": "${rc2_02_evidence_csv}",
|
|
193
|
+
"stakeholders": ["provider"]
|
|
194
|
+
}
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"rule_id": "R-C2-03",
|
|
199
|
+
"dimension": "data_source_trust",
|
|
200
|
+
"trigger": "Guard queries Progress status without verifying Machine publish state",
|
|
201
|
+
"cases": [
|
|
202
|
+
{
|
|
203
|
+
"when": { "all": [{ "field": "queries_progress", "op": "eq", "value": true }, { "field": "has_witness", "op": "eq", "value": true }, { "field": "scene_host_object", "op": "eq", "value": "Machine" }] },
|
|
204
|
+
"level": "medium",
|
|
205
|
+
"title": "Progress data depends on Machine immutability",
|
|
206
|
+
"description": "Guard queries Progress status via witness, and the Guard is bound to a Machine.If the Machine is not published (bPublished=false), the Provider can modify the Machine node structure, causing node names validated by the Guard to become invalid or be renamed. Progress's current node name, node time, etc. all depend on the Machine's node definitions.",
|
|
207
|
+
"scenario": "Provider modifies Machine node names to invalidate Guard verification",
|
|
208
|
+
"mitigation": "1) Ensure the Machine is published (bPublished=true) before binding the Guard;2) Query the Machine.bPublished field in the Guard to verify;3) Use node IDs instead of node names for comparison",
|
|
209
|
+
"stakeholders": ["customer"]
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"rule_id": "R-C2-04",
|
|
215
|
+
"dimension": "data_source_trust",
|
|
216
|
+
"trigger": "Guard uses witness query and the query parameter requires type conversion (e.g. Address → U64 timestamp key)",
|
|
217
|
+
"cases": [
|
|
218
|
+
{
|
|
219
|
+
"when": { "all": [{ "field": "has_witness", "op": "eq", "value": true }, { "any": [{ "field": "rc2_04_queries_repo", "op": "eq", "value": true }, { "field": "rc2_04_queries_progress_history", "op": "eq", "value": true }] }] },
|
|
220
|
+
"level": "medium",
|
|
221
|
+
"title": "witness query parameter requires type translation (missing will cause type mismatch or wrong comparison)",
|
|
222
|
+
"description": "Guard queries object fields via witness, but the query parameter type may not match the type declared in table.\nTypical scenarios:\n - Repository.data query: the key may be of Address type (vector<u8> address representation in Move), but the actual semantics is a U64 timestamp, requiring convert_number_address translation\n - Progress.history query: Forward ID may need to be converted from String to Address\n - Order field query: some ID fields may be stored as Address but need U256 for comparison${rc2_04_conversion_note}",
|
|
223
|
+
"scenario": "Query parameter type does not match the parameters type defined by GUARDQUERY, causing creation failure or runtime comparison error",
|
|
224
|
+
"mitigation": "1) Query GUARDQUERY to confirm the parameters type and return type of each query instruction;\n2) If table declares Address but the query needs U64, use convert_number_address to translate;\n3) Use wowok_buildin_info info='guard instructions' to verify parameter types;\n4) Verify type compatibility via schema_query before creation",
|
|
225
|
+
"evidence": "${rc2_04_conversion_evidence}",
|
|
226
|
+
"stakeholders": ["provider", "customer"]
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"rule_id": "R-C3-01",
|
|
232
|
+
"dimension": "submission_forgery",
|
|
233
|
+
"trigger": "Guard depends on submitted data but does not verify signer identity (no Signer check=high; with Signer check=info downgrade)",
|
|
234
|
+
"cases": [
|
|
235
|
+
{
|
|
236
|
+
"when": { "all": [{ "field": "has_submission", "op": "eq", "value": true }, { "field": "scene_binding_field", "op": "neq", "value": "voting_guard" }, { "field": "rc3_01_sharing_exempt", "op": "eq", "value": false }, { "field": "scene_id", "op": "eq", "value": "machine_forward_guard" }, { "field": "has_signer_check", "op": "eq", "value": false }] },
|
|
237
|
+
"level": "medium",
|
|
238
|
+
"title": "Submitted data not bound to signer identity (Forward scenario implicitly verified by permissionIndex)",
|
|
239
|
+
"description": "Guard accepts runtime-submitted data (b_submission=true), and root does not explicitly verify Signer.This Guard is used for Machine Forward; Forward's permissionIndex/namedOperator already implicitly verifies operator identity, so the Signer binding risk is reduced. But permissionIndex only verifies 'operator has permission', not 'submitted data belongs to operator' — for example, a merchant holding permissionIndex can still submit someone else's credentials.",
|
|
240
|
+
"scenario": "In-permission forgery: an authorized operator submits someone else's data (e.g. someone else's Merkle Root)",
|
|
241
|
+
"mitigation": "1) If the submitted data should belong to the operator (e.g. the operator's address), it is still recommended to add context(Signer) binding;2) If the submitted data is a public credential (e.g. Merkle Root string), the current risk is acceptable;3) Use retained_submission to retain submitted data for later audit",
|
|
242
|
+
"stakeholders": ["customer", "provider"]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"when": { "all": [{ "field": "has_submission", "op": "eq", "value": true }, { "field": "scene_binding_field", "op": "neq", "value": "voting_guard" }, { "field": "rc3_01_sharing_exempt", "op": "eq", "value": false }, { "field": "has_signer_check", "op": "eq", "value": false }] },
|
|
246
|
+
"level": "high",
|
|
247
|
+
"title": "Submitted data not bound to signer identity",
|
|
248
|
+
"description": "Guard accepts runtime-submitted data (b_submission=true), but does not verify whether the submitter is the current transaction signer.An attacker can submit someone else's data (e.g. someone else's address, someone else's credentials) to pass the Guard.Type3 submitted objects are isomorphic with Type1 at the native layer (TYPE_QUERY+TYPE_CONSTANT), the only difference being that the value is injected by submission, so identity must be bound via logical constraints.",
|
|
249
|
+
"scenario": "Identity forgery: attacker submits someone else's address to impersonate an authorized user",
|
|
250
|
+
"mitigation": "1) Add context(Signer) binding with the submitted data for verification;2) Use vec_contains_address to verify the signer is in the whitelist;3) Use Passport credentials instead of bare address submission",
|
|
251
|
+
"stakeholders": ["customer", "provider"],
|
|
252
|
+
"exposure": {
|
|
253
|
+
"loss_parties": [
|
|
254
|
+
{ "role": "merchant", "basis": "An attacker who passes the unbound Guard exercises the operation it gates as if authorized — the project's funds and objects are exposed to unauthorized execution." },
|
|
255
|
+
{ "role": "buyer", "basis": "Forged submissions can push the buyer's order through states the buyer never authorized." }
|
|
256
|
+
],
|
|
257
|
+
"gain_paths": [
|
|
258
|
+
{
|
|
259
|
+
"role": "neutral",
|
|
260
|
+
"path": "The attacker submits someone else's address or credential, the unbound check passes, and the gated operation (forward/claim/allocation) executes for the attacker's benefit.",
|
|
261
|
+
"viability": "viable",
|
|
262
|
+
"gate": "The Guard verifies submitted values but never ties them to the transaction signer — nothing on-chain blocks the forged-submission pass."
|
|
263
|
+
}
|
|
264
|
+
]
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"when": { "all": [{ "field": "has_submission", "op": "eq", "value": true }, { "field": "scene_binding_field", "op": "neq", "value": "voting_guard" }, { "field": "rc3_01_sharing_exempt", "op": "eq", "value": false }, { "field": "has_signer_check", "op": "eq", "value": true }] },
|
|
269
|
+
"level": "low",
|
|
270
|
+
"title": "Submitted data is indirectly bound via context(Signer) (confirm the binding direction is correct)",
|
|
271
|
+
"description": "Guard accepts runtime-submitted data, and the root subtree contains a context(Signer) check, forming an indirect binding between submitted data and signer, reducing forgery risk.But manual confirmation is needed: the constant compared with context(Signer) is the correct role (e.g. Provider address rather than Customer address), and the submitted data should indeed be provided by that signer. See R-C4-01 Signer direction risk.",
|
|
272
|
+
"scenario": "Indirect binding to confirm: whether the Signer check direction matches the submitted data ownership",
|
|
273
|
+
"mitigation": "1) Confirm context(Signer) is compared with the correct table constant (Provider address rather than Customer address);2) Confirm the source role of the submitted data matches the Signer check;3) For stricter binding, use query to verify the submitter's on-chain identity",
|
|
274
|
+
"stakeholders": ["customer", "provider"]
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"rule_id": "R-C3-02",
|
|
280
|
+
"dimension": "submission_forgery",
|
|
281
|
+
"trigger": "voting_guard weight comes from submitted data without verifying source",
|
|
282
|
+
"cases": [
|
|
283
|
+
{
|
|
284
|
+
"when": { "all": [{ "field": "scene_binding_field", "op": "eq", "value": "voting_guard" }, { "field": "rc3_02_numeric_count", "op": "gt", "value": 0 }] },
|
|
285
|
+
"level": "critical",
|
|
286
|
+
"title": "Voting weight comes from user submission and may be forged",
|
|
287
|
+
"description": "voting_guard weight data comes from table entries with b_submission=true (Type3 submitted values).If the weight is not verified through EntityRegistrar or other trusted sources, a voter can submit arbitrarily high weights to manipulate the voting result.Type3 submitted values are only validated by type byte (value[0]) at the native layer; value range and source are not checked.",
|
|
288
|
+
"scenario": "Weight forgery: voters submit fake high scores to manipulate the arbitration result",
|
|
289
|
+
"mitigation": "1) Weights should be queried from EntityRegistrar rather than submitted by users;2) Use query(entity.records) to obtain on-chain registered reputation scores;3) Verify in the Guard that the submitted weight matches the on-chain record",
|
|
290
|
+
"evidence": "Submitted numeric entries: ${rc3_02_numeric_list}",
|
|
291
|
+
"stakeholders": ["arbitrator"],
|
|
292
|
+
"exposure": {
|
|
293
|
+
"loss_parties": [
|
|
294
|
+
{ "role": "buyer", "basis": "A forged voting weight can swing the arbitration ruling — the buyer may be denied a deserved payout or charged a wrongful one." },
|
|
295
|
+
{ "role": "merchant", "basis": "The same manipulated ruling can force an unjustified compensation payout from the merchant side." }
|
|
296
|
+
],
|
|
297
|
+
"gain_paths": [
|
|
298
|
+
{
|
|
299
|
+
"role": "neutral",
|
|
300
|
+
"path": "A voter submits an arbitrarily high weight in the passport; the voting count consumes the forged value directly.",
|
|
301
|
+
"viability": "viable",
|
|
302
|
+
"gate": "Submitted numeric entries are only type-byte validated — no on-chain check ties the weight to a trusted source."
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"rule_id": "R-C3-03",
|
|
311
|
+
"dimension": "submission_forgery",
|
|
312
|
+
"trigger": "Guard contains Address entries with b_submission=true; the runtime submitted object type may not match expectations",
|
|
313
|
+
"cases": [
|
|
314
|
+
{
|
|
315
|
+
"when": { "all": [{ "field": "rc3_03_submitted_addr_count", "op": "gt", "value": 0 }, { "field": "root_has_query", "op": "eq", "value": true }, { "field": "rc3_03_no_type_count", "op": "gt", "value": 0 }] },
|
|
316
|
+
"level": "medium",
|
|
317
|
+
"title": "Submitted object missing object_type annotation; runtime type validation relies on native inference",
|
|
318
|
+
"description": "Guard contains ${rc3_03_submitted_addr_count} Address entries with b_submission=true (Type3 submitted objects).The native layer (passport.rs#parse_table_items) only checks the value[0] type byte for submission; object_type is derived at runtime by wobject_type and does not strictly validate the actual submitted object type.\nWarning: ${rc3_03_no_type_count} entries are missing object_type annotation, semantics are unclear.",
|
|
319
|
+
"scenario": "Type mismatch: submitting a wrong-typed object causes query to return unexpected values",
|
|
320
|
+
"mitigation": "1) Annotate object_type for all Address entries with b_submission=true;2) object_type should match the object type expected by the query instruction;3) Indirectly verify the object type via query results in Guard logic (e.g. query order.amount to verify it is an Order)",
|
|
321
|
+
"evidence": "${rc3_03_evidence}",
|
|
322
|
+
"stakeholders": ["customer", "provider"]
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"when": { "all": [{ "field": "rc3_03_submitted_addr_count", "op": "gt", "value": 0 }, { "field": "root_has_query", "op": "eq", "value": true }, { "field": "rc3_03_no_type_count", "op": "eq", "value": 0 }] },
|
|
326
|
+
"level": "low",
|
|
327
|
+
"title": "Submitted object type validation relies on runtime native inference",
|
|
328
|
+
"description": "Guard contains ${rc3_03_submitted_addr_count} Address entries with b_submission=true (Type3 submitted objects).The native layer (passport.rs#parse_table_items) only checks the value[0] type byte for submission; object_type is derived at runtime by wobject_type and does not strictly validate the actual submitted object type.\nobject_type is annotated, but still confirm the annotation matches what the query expects.",
|
|
329
|
+
"scenario": "Type mismatch: submitting a wrong-typed object causes query to return unexpected values",
|
|
330
|
+
"mitigation": "1) Annotate object_type for all Address entries with b_submission=true;2) object_type should match the object type expected by the query instruction;3) Indirectly verify the object type via query results in Guard logic (e.g. query order.amount to verify it is an Order)",
|
|
331
|
+
"evidence": "${rc3_03_evidence}",
|
|
332
|
+
"stakeholders": ["customer", "provider"]
|
|
333
|
+
}
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"rule_id": "R-C3-04",
|
|
338
|
+
"dimension": "binding_risk",
|
|
339
|
+
"trigger": "Repository write_guard does not verify id_from_submission type",
|
|
340
|
+
"cases": [
|
|
341
|
+
{
|
|
342
|
+
"when": { "field": "scene_binding_field", "op": "eq", "value": "write_guard" },
|
|
343
|
+
"level": "high",
|
|
344
|
+
"title": "Repository write_guard must verify id_from_submission type",
|
|
345
|
+
"description": "The table entry referenced by Repository write_guard's id_from_submission must be of Address type (Type3 submitted object).The entry referenced by data_from_submission must match the Repository value_type.Type mismatch will cause write failure or data corruption. The write_guard submission contains both id and data parts; the native layer distinguishes them by op_code, but value types must match the table declaration.",
|
|
346
|
+
"scenario": "Type mismatch: write failure or data corruption",
|
|
347
|
+
"mitigation": "1) Confirm the entry referenced by id_from_submission has value_type=Address;2) Confirm the entry referenced by data_from_submission has value_type matching the Repository;3) Cover write scenarios in gen_passport tests",
|
|
348
|
+
"stakeholders": ["provider"]
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
"rule_id": "R-C3-05",
|
|
354
|
+
"dimension": "submission_forgery",
|
|
355
|
+
"trigger": "Guard accepts a runtime-submitted Order/Progress/Arb object (Type3) but does NOT verify the submitted object belongs to the current project (Machine or Service). The WoWok runtime does NOT enforce any binding between the submitted order_id and the actual Progress being forwarded — the guard verification receives only the caller-provided submission bytes, never the Progress object under advancement. A caller can therefore submit an unrelated order_id from a DIFFERENT project while forwarding a different Progress, causing witness=100 (Order->Progress) to evaluate against foreign data.",
|
|
356
|
+
"cases": [
|
|
357
|
+
{
|
|
358
|
+
"when": { "all": [{ "field": "rc3_05_applies", "op": "eq", "value": true }, { "field": "rc3_05_critical", "op": "eq", "value": true }] },
|
|
359
|
+
"level": "critical",
|
|
360
|
+
"title": "Submitted Order/Progress/Arb is NOT verified to belong to the current project (cross-project bypass — CRITICAL trust-boundary gap)",
|
|
361
|
+
"description": "Guard accepts runtime-submitted Order/Progress/Arb object(s) [${rc3_05_unbound_csv}] but the root does NOT verify the submitted object belongs to the current project (no query of order.service/order.machine/progress.machine/arb.service compared to a project constant).\n\nTRUST-BOUNDARY GAP (verified via Move source):\n - The Passport submission is built by the CALLER, not auto-injected by the runtime\n - the guard verification receives ONLY the caller-provided submission bytes — it never sees the Progress/Order actually being forwarded\n - the passport-driven forward performs NO linkage check between the passport submission and the Progress under advancement\n - Even the order forward's E_ORDER_NOT_MATCH only checks the separate `order:&Order` parameter, NOT the order_id embedded in the passport submission\n\nEXPLOIT (scene=${rc3_05_scene_label}):\n 1. Attacker holds Order Y from project B (where progress.current_time is old enough to pass the time-lock)\n 2. Attacker calls forward on Order X's Progress (project A, freshly entered the node)\n 3. Attacker submits Order Y's ID in the passport (lying about which order is being forwarded)\n 4. Guard's witness=100 reads Order Y's Progress -> time-lock passes (Order Y is old)\n 5. forward actually executes on Order X's Progress -> TIME-LOCK BYPASSED\n\nThis is distinct from R-C3-01 (Signer binding — WHO can submit) and R-C3-03 (type matching — WHAT type is submitted). R-C3-05 addresses WHETHER the submitted object belongs to the current project — a third orthogonal axis of submission trust. Even with R-C3-01 satisfied (authorized Signer) and R-C3-03 satisfied (correct type), the Signer can still submit an unrelated project's object.",
|
|
362
|
+
"scenario": "Cross-project bypass: authorized signer submits an unrelated project's order/progress/arb to bypass time-lock, status, or allocation conditions",
|
|
363
|
+
"mitigation": "Add a project-binding check to the root (wrap existing root in logic_and):\n - For submitted Order: add logic_equal[query(1563: order.service), identifier[N](project_service_address)] — RECOMMENDED (service is the canonical project anchor)\n - For submitted Order: add logic_equal[query(1560: order.machine), identifier[N](project_machine_address)] — alternative (machine anchor)\n - For submitted Progress: add logic_equal[query(1250: progress.machine), identifier[N](project_machine_address)]\n - For submitted Arb: add logic_equal[query(1402: arb.service), identifier[N](project_service_address)]\n - Use witness=102 (TypeOrderService) on the submitted Order to derive the Service, then compare to the project service constant\n\nIntentional cross-project exception: if the Guard is DESIGNED to accept cross-project submissions (rare), document this explicitly in the description and add a binding_hint annotation 'cross_project_intentional:true' to suppress this rule.",
|
|
364
|
+
"evidence": "Unbound submitted project-relevant entries: ${rc3_05_unbound_csv}. Scene: ${rc3_05_scene_label}. Missing project-binding queries: none of [1563(order.service), 1560(order.machine), 1250(progress.machine), 1402(arb.service)] present in root.",
|
|
365
|
+
"stakeholders": ["customer", "provider", "arbitrator"],
|
|
366
|
+
"exposure": {
|
|
367
|
+
"loss_parties": [
|
|
368
|
+
{ "role": "merchant", "basis": "Time-lock, status and allocation conditions stop protecting the project — funds can be released before the merchant's obligations are met." },
|
|
369
|
+
{ "role": "buyer", "basis": "The buyer's order protections (time-locks, status gates) can be bypassed with a foreign project's object." }
|
|
370
|
+
],
|
|
371
|
+
"gain_paths": [
|
|
372
|
+
{
|
|
373
|
+
"role": "neutral",
|
|
374
|
+
"path": "The caller submits an unrelated project's order/progress id in the passport while forwarding the real Progress; the Guard witness reads the foreign object and passes.",
|
|
375
|
+
"viability": "viable",
|
|
376
|
+
"gate": "The runtime never links the passport submission to the Progress under advancement — the bypass executes exactly as described in the exploit."
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"when": { "all": [{ "field": "rc3_05_applies", "op": "eq", "value": true }, { "field": "rc3_05_critical", "op": "eq", "value": false }] },
|
|
383
|
+
"level": "high",
|
|
384
|
+
"title": "Submitted Order/Progress/Arb is NOT verified to belong to the current project (cross-project bypass — CRITICAL trust-boundary gap)",
|
|
385
|
+
"description": "Guard accepts runtime-submitted Order/Progress/Arb object(s) [${rc3_05_unbound_csv}] but the root does NOT verify the submitted object belongs to the current project (no query of order.service/order.machine/progress.machine/arb.service compared to a project constant).\n\nTRUST-BOUNDARY GAP (verified via Move source):\n - The Passport submission is built by the CALLER, not auto-injected by the runtime\n - the guard verification receives ONLY the caller-provided submission bytes — it never sees the Progress/Order actually being forwarded\n - the passport-driven forward performs NO linkage check between the passport submission and the Progress under advancement\n - Even the order forward's E_ORDER_NOT_MATCH only checks the separate `order:&Order` parameter, NOT the order_id embedded in the passport submission\n\nEXPLOIT (scene=${rc3_05_scene_label}):\n 1. Attacker holds Order Y from project B (where progress.current_time is old enough to pass the time-lock)\n 2. Attacker calls forward on Order X's Progress (project A, freshly entered the node)\n 3. Attacker submits Order Y's ID in the passport (lying about which order is being forwarded)\n 4. Guard's witness=100 reads Order Y's Progress -> time-lock passes (Order Y is old)\n 5. forward actually executes on Order X's Progress -> TIME-LOCK BYPASSED\n\nThis is distinct from R-C3-01 (Signer binding — WHO can submit) and R-C3-03 (type matching — WHAT type is submitted). R-C3-05 addresses WHETHER the submitted object belongs to the current project — a third orthogonal axis of submission trust. Even with R-C3-01 satisfied (authorized Signer) and R-C3-03 satisfied (correct type), the Signer can still submit an unrelated project's object.",
|
|
386
|
+
"scenario": "Cross-project bypass: authorized signer submits an unrelated project's order/progress/arb to bypass time-lock, status, or allocation conditions",
|
|
387
|
+
"mitigation": "Add a project-binding check to the root (wrap existing root in logic_and):\n - For submitted Order: add logic_equal[query(1563: order.service), identifier[N](project_service_address)] — RECOMMENDED (service is the canonical project anchor)\n - For submitted Order: add logic_equal[query(1560: order.machine), identifier[N](project_machine_address)] — alternative (machine anchor)\n - For submitted Progress: add logic_equal[query(1250: progress.machine), identifier[N](project_machine_address)]\n - For submitted Arb: add logic_equal[query(1402: arb.service), identifier[N](project_service_address)]\n - Use witness=102 (TypeOrderService) on the submitted Order to derive the Service, then compare to the project service constant\n\nIntentional cross-project exception: if the Guard is DESIGNED to accept cross-project submissions (rare), document this explicitly in the description and add a binding_hint annotation 'cross_project_intentional:true' to suppress this rule.",
|
|
388
|
+
"evidence": "Unbound submitted project-relevant entries: ${rc3_05_unbound_csv}. Scene: ${rc3_05_scene_label}. Missing project-binding queries: none of [1563(order.service), 1560(order.machine), 1250(progress.machine), 1402(arb.service)] present in root.",
|
|
389
|
+
"stakeholders": ["customer", "provider", "arbitrator"],
|
|
390
|
+
"exposure": {
|
|
391
|
+
"loss_parties": [
|
|
392
|
+
{ "role": "merchant", "basis": "Time-lock, status and allocation conditions stop protecting the project — funds can be released before the merchant's obligations are met." },
|
|
393
|
+
{ "role": "buyer", "basis": "The buyer's order protections (time-locks, status gates) can be bypassed with a foreign project's object." }
|
|
394
|
+
],
|
|
395
|
+
"gain_paths": [
|
|
396
|
+
{
|
|
397
|
+
"role": "neutral",
|
|
398
|
+
"path": "The caller submits an unrelated project's order/progress id in the passport while forwarding the real Progress; the Guard witness reads the foreign object and passes.",
|
|
399
|
+
"viability": "viable",
|
|
400
|
+
"gate": "The runtime never links the passport submission to the Progress under advancement — the bypass executes exactly as described in the exploit."
|
|
401
|
+
}
|
|
402
|
+
]
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
]
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
"rule_id": "R-C3-06",
|
|
409
|
+
"dimension": "binding_risk",
|
|
410
|
+
"trigger": "Guard is bound to Service order_allocators (service_order_allocators_guard scene). In this scene the Guard decides IF allocation happens, while sharing.who decides WHERE funds go. If sharing.who=Signer, the transaction caller receives the funds — so a Guard that does NOT bind context(Signer) lets ANYONE who passes the Guard steal 100% of the order funds. This is a Guard+sharing coupling risk: neither piece alone reveals the theft — only their combination.",
|
|
411
|
+
"cases": [
|
|
412
|
+
{
|
|
413
|
+
"when": { "all": [{ "field": "rc3_06_applies", "op": "eq", "value": true }, { "field": "rc3_06_signer_sharing", "op": "eq", "value": true }] },
|
|
414
|
+
"level": "critical",
|
|
415
|
+
"title": "allocators Guard without Signer binding — ${rc3_06_title_suffix}",
|
|
416
|
+
"description": "Guard is bound to Service order_allocators but does NOT verify context(Signer). In the allocators scene, sharing.who determines the fund recipient:\n - sharing.who=Signer → funds flow to the CALLER (transaction signer)\n - sharing.who=Entity → funds flow to a FIXED address (Treasury/personal)\n - sharing.who=GuardIdentifier → funds flow to the submitted constrained object (e.g. an Order), receivable only by that object's owner (object receipt = owner receipt); see RC-FIND-03 residual in the recipient constraint audit\n\nWhen sharing.who=Signer and the Guard does not bind Signer, ANY caller who passes the Guard receives the order funds — a direct theft. Even an authorized caller is unnecessary: the attacker only needs to pass the Guard's condition (e.g. submit any completed order_id), then the funds go to their own address.\n\nThis is distinct from R-C3-01 (generic Signer binding) and R-C3-05 (cross-project bypass). R-C3-06 addresses the allocators-specific Guard+sharing coupling: the SAFE design uses sharing.who=Entity so the recipient is fixed, making Guard Signer binding unnecessary.\n\nsharing_recipients hint: ${rc3_06_recipients_label}",
|
|
417
|
+
"scenario": "Fund theft: attacker passes the allocators Guard (e.g. submits a completed order_id) and sharing.who=Signer routes 100% of the order funds to the attacker's address",
|
|
418
|
+
"mitigation": "TWO mitigation options:\n (A) Traditional: add context(Signer) binding to the Guard root (logic_equal[context(Signer), identifier[N](authorized_address)]) so only the authorized recipient can trigger allocation.\n (B) PREFERRED: use sharing.who=Entity (Treasury object or fixed personal address) in the Allocator's sharing config. Funds then always flow to the designated recipient regardless of who triggers allocation — the Guard does NOT need to bind Signer. This is more robust because it does not depend on Guard correctness.\n\nDesign checklist when using sharing.who=Entity:\n - If Entity points to a Treasury object, verify the Treasury's permission is consistent with the Service's permission (different permissions = different permission organizations = minor risk).\n - allocators require unique guard addresses: create separate Guard objects (identical root/table, different descriptions) for each allocator.\n - First-match-wins: only the first Allocator whose Guard passes executes; multiple allocators represent alternative strategies, not a simultaneous split.\n - Still add order.service project binding (query 1563) to prevent cross-project bypass (R-C3-05) triggering premature allocation.",
|
|
419
|
+
"evidence": "Scene: service_order_allocators_guard. Guard binds Signer: no. sharing_recipients: ${rc3_06_recipients_label}. Level rationale: ${rc3_06_level_rationale}.",
|
|
420
|
+
"stakeholders": ["provider", "customer"],
|
|
421
|
+
"exposure": {
|
|
422
|
+
"loss_parties": [
|
|
423
|
+
{ "role": "merchant", "basis": "The order's full fund allocation can be redirected away from the configured recipients on the very first qualifying call." },
|
|
424
|
+
{ "role": "buyer", "basis": "The buyer's payment is distributed to an attacker instead of the intended revenue/refund split." }
|
|
425
|
+
],
|
|
426
|
+
"gain_paths": [
|
|
427
|
+
{
|
|
428
|
+
"role": "neutral",
|
|
429
|
+
"path": "Any caller who passes the allocators Guard (e.g. submits any completed order_id) triggers the allocation; sharing.who=Signer routes 100% of the order funds to the caller's own address.",
|
|
430
|
+
"viability": "viable",
|
|
431
|
+
"gate": "The Guard never compares context(Signer) to an authorized party, so passing the Guard's condition is the only requirement — the theft path is executable by anyone."
|
|
432
|
+
}
|
|
433
|
+
]
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
"when": { "all": [{ "field": "rc3_06_applies", "op": "eq", "value": true }, { "field": "rc3_06_signer_sharing", "op": "eq", "value": false }] },
|
|
438
|
+
"level": "medium",
|
|
439
|
+
"title": "allocators Guard without Signer binding — ${rc3_06_title_suffix}",
|
|
440
|
+
"description": "Guard is bound to Service order_allocators but does NOT verify context(Signer). In the allocators scene, sharing.who determines the fund recipient:\n - sharing.who=Signer → funds flow to the CALLER (transaction signer)\n - sharing.who=Entity → funds flow to a FIXED address (Treasury/personal)\n - sharing.who=GuardIdentifier → funds flow to the submitted constrained object (e.g. an Order), receivable only by that object's owner (object receipt = owner receipt); see RC-FIND-03 residual in the recipient constraint audit\n\nWhen sharing.who=Signer and the Guard does not bind Signer, ANY caller who passes the Guard receives the order funds — a direct theft. Even an authorized caller is unnecessary: the attacker only needs to pass the Guard's condition (e.g. submit any completed order_id), then the funds go to their own address.\n\nThis is distinct from R-C3-01 (generic Signer binding) and R-C3-05 (cross-project bypass). R-C3-06 addresses the allocators-specific Guard+sharing coupling: the SAFE design uses sharing.who=Entity so the recipient is fixed, making Guard Signer binding unnecessary.\n\nsharing_recipients hint: ${rc3_06_recipients_label}",
|
|
441
|
+
"scenario": "Fund theft: attacker passes the allocators Guard (e.g. submits a completed order_id) and sharing.who=Signer routes 100% of the order funds to the attacker's address",
|
|
442
|
+
"mitigation": "TWO mitigation options:\n (A) Traditional: add context(Signer) binding to the Guard root (logic_equal[context(Signer), identifier[N](authorized_address)]) so only the authorized recipient can trigger allocation.\n (B) PREFERRED: use sharing.who=Entity (Treasury object or fixed personal address) in the Allocator's sharing config. Funds then always flow to the designated recipient regardless of who triggers allocation — the Guard does NOT need to bind Signer. This is more robust because it does not depend on Guard correctness.\n\nDesign checklist when using sharing.who=Entity:\n - If Entity points to a Treasury object, verify the Treasury's permission is consistent with the Service's permission (different permissions = different permission organizations = minor risk).\n - allocators require unique guard addresses: create separate Guard objects (identical root/table, different descriptions) for each allocator.\n - First-match-wins: only the first Allocator whose Guard passes executes; multiple allocators represent alternative strategies, not a simultaneous split.\n - Still add order.service project binding (query 1563) to prevent cross-project bypass (R-C3-05) triggering premature allocation.",
|
|
443
|
+
"evidence": "Scene: service_order_allocators_guard. Guard binds Signer: no. sharing_recipients: ${rc3_06_recipients_label}. Level rationale: ${rc3_06_level_rationale}.",
|
|
444
|
+
"stakeholders": ["provider", "customer"]
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"rule_id": "R-C4-01",
|
|
450
|
+
"dimension": "system_context_risk",
|
|
451
|
+
"trigger": "Guard contains context(Signer) check; need to confirm comparison direction (== vs !=) and compared object role",
|
|
452
|
+
"cases": [
|
|
453
|
+
{
|
|
454
|
+
"when": { "field": "has_signer_check", "op": "eq", "value": true },
|
|
455
|
+
"level": "medium",
|
|
456
|
+
"title": "Signer check direction needs manual confirmation (comparison operator and role match)",
|
|
457
|
+
"description": "Guard contains a context(Signer) check. Signer is a Type4 system context, from TransactionContext.sender() (transaction initiator address).\nDetected comparison: ${rc4_01_comparison_detail}\nManual confirmation required:\n 1) Whether the comparison direction is correct: use == for identity verification (Signer == authorized address), use != for exclusion (Signer != blacklist address)\n 2) Whether the compared object role is correct: buy_guard should compare the Customer address, Forward.guard may compare the Provider address\n 3) Wrong direction causes reverse effect: == blacklist address would only allow blacklisted users",
|
|
458
|
+
"scenario": "Wrong direction: Signer == blacklist address would only allow blacklisted users",
|
|
459
|
+
"mitigation": "1) Confirm logic_equal is used for identity verification (Signer == authorized address);2) Confirm logic_not_equal is used for exclusion (Signer != blacklist address);3) Confirm the compared table constant is the address of the correct role;4) Cover both expected-pass and expected-fail scenarios in gen_passport tests",
|
|
460
|
+
"evidence": "Comparison: ${rc4_01_comparison_ops}",
|
|
461
|
+
"stakeholders": ["customer", "provider"]
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
"rule_id": "R-C4-02",
|
|
467
|
+
"dimension": "system_context_risk",
|
|
468
|
+
"trigger": "Guard uses context(Clock) for precise boundary time-lock comparison",
|
|
469
|
+
"cases": [
|
|
470
|
+
{
|
|
471
|
+
"when": { "all": [{ "field": "has_clock_check", "op": "eq", "value": true }, { "any": [{ "field": "rc4_02_has_greater_or_equal", "op": "eq", "value": true }, { "field": "rc4_02_has_greater", "op": "eq", "value": true }] }] },
|
|
472
|
+
"level": "low",
|
|
473
|
+
"title": "Clock time-lock should have tolerance to avoid boundary invalidation from validator block-time variance",
|
|
474
|
+
"description": "Guard uses context(Clock) for time-lock comparison. Clock comes from the timestamp_ms field (U64 millisecond timestamp) of system shared object 0x6.The Wow on-chain timestamp is produced by validator consensus and has a slight deviation from real time (usually < 1 second), and block-time variance may cause timestamp jumps. Using precise boundaries (>= or ==) may cause:\n - The time-lock expiration transaction is packaged exactly at the moment but fails due to slight timestamp deviation\n - Or conversely, slight deviation causes the time-lock to pass early\nIt is recommended to use > instead of >=, or add a small tolerance constant.",
|
|
475
|
+
"scenario": "Timestamp variance: validator block-time deviation causes boundary transactions to fail or pass early",
|
|
476
|
+
"mitigation": "1) Use logic_as_u256_greater (>) instead of greater_or_equal (>=) for expiration judgment;2) Or add a small tolerance constant (e.g. 1000ms) in calc_number_add;3) Time-locks should not rely on second-level precision; reserve minute-level tolerance;4) Design timeout Forward nodes in the Machine as a fallback",
|
|
477
|
+
"evidence": "Comparison: ${rc4_02_comparison_ops}",
|
|
478
|
+
"stakeholders": ["customer", "provider"]
|
|
479
|
+
}
|
|
480
|
+
]
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"rule_id": "R-C4-03",
|
|
484
|
+
"dimension": "system_context_risk",
|
|
485
|
+
"trigger": "Guard uses context(Guard) self-reference",
|
|
486
|
+
"cases": [
|
|
487
|
+
{
|
|
488
|
+
"when": { "field": "has_guard_self_ref", "op": "eq", "value": true },
|
|
489
|
+
"level": "low",
|
|
490
|
+
"title": "Guard uses context(Guard) self-reference (rare scenario, needs special explanation)",
|
|
491
|
+
"description": "Guard contains a context(Guard) node. Guard is a Type4 system context, returning the ObjectID of the currently verified Guard object itself.\nThis is a rare scenario, typically used for:\n 1) Guard referencing its own address as a replacement for a table constant (avoiding hardcoding)\n 2) Identifying the current Guard in a rely combination (rare)\nNeed to confirm whether the use of context(Guard) is necessary and whether the comparison object is correct.",
|
|
492
|
+
"scenario": "Self-reference misuse: context(Guard) comparing wrong object causes logic invalidation",
|
|
493
|
+
"mitigation": "1) Confirm the context(Guard) comparison object is the Guard ObjectID rather than an address constant;2) Evaluate whether self-reference is truly needed; usually a table constant can replace it;3) Verify in gen_passport tests that self-reference behavior meets expectations",
|
|
494
|
+
"stakeholders": ["provider"]
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
"rule_id": "R-C4-04",
|
|
500
|
+
"dimension": "system_context_risk",
|
|
501
|
+
"trigger": "Guard uses logic_equal[context(Signer), identifier[N](fixed_address)] — Level 1 strict single-identity Signer binding. Only ONE address can pass the Guard, and because Guards are immutable, changing the authorized address requires rebuilding the Guard and migrating all references. This creates a convenience trade-off: maximum security but maximum inflexibility (key loss or personnel change permanently blocks the operation).",
|
|
502
|
+
"cases": [
|
|
503
|
+
{
|
|
504
|
+
"when": { "field": "rc4_04_detected", "op": "eq", "value": true },
|
|
505
|
+
"level": "low",
|
|
506
|
+
"title": "Level 1 strict single-identity Signer binding — convenience trade-off (consider Level 2/3 alternatives)",
|
|
507
|
+
"description": "Guard uses logic_equal[context(Signer), identifier[${rc4_04_entry_identifier}](fixed address)] — only the address \"${rc4_04_entry_value}\" can pass.\nThis is Level 1 strict single-identity binding: maximally secure but maximally inconvenient.\nGuards are immutable on-chain. If the authorized address becomes unavailable (key loss, personnel change, role rotation), the Guard permanently blocks the operation — the only recovery is to build a new Guard and migrate ALL references (Machine forward guards, Service buy_guard, allocators, etc.).\n\nThree verifier constraint levels trade off security vs convenience:\n - Level 1 (current): strict single-identity — one address, no flexibility (AVOID unless justified)\n - Level 2: identity-set — logic_or of multiple valid identities (e.g. order.owner OR order.agent; permission.owner OR permission.admin). Recommended for role-based access.\n - Level 3: scene-combined — verify whether Signer binding is even needed. Many scenes (allocators with sharing.who=Entity, machine forward with permissionIndex) already ensure safety without Signer binding.\n\nUse Level 1 only when: (a) the role is permanently tied to one address, AND (b) the designer explicitly accepts the immutability lock-in risk. Otherwise prefer Level 2 or Level 3.",
|
|
508
|
+
"scenario": "Immutability lock-in: authorized address becomes unavailable, Guard permanently blocks the operation, requiring full Guard rebuild and reference migration",
|
|
509
|
+
"mitigation": "Consider these alternatives before settling on Level 1 strict binding:\n (A) Level 2 identity-set (RECOMMENDED for role-based access): use logic_or to allow multiple valid identities.\n - Order holder: logic_or[logic_equal[query(1562: order.owner), context(Signer)], query(1567: order.agent has, parameters: [context(Signer)])]\n - Service provider: logic_or[logic_equal[query(1002: permission.owner), context(Signer)], query(1004: permission.admin has, parameters: [context(Signer)])]\n - Dynamic permission (survives rotation): submit permission address, verify query(1488: service.permission) == submitted, then check 1002/1004\n (B) Level 3 scene-combined: evaluate whether Signer binding is needed at all.\n - If using allocators with sharing.who=Entity (Treasury): funds flow to a fixed recipient regardless of caller — no Signer binding needed (R-C3-06 safe)\n - If using machine forward: permissionIndex already verifies operator identity — Signer binding may be redundant\n (C) If Level 1 is truly required: document the justification in the Guard description and ensure a key-recovery / address-rotation plan exists.",
|
|
510
|
+
"evidence": "Level 1 strict binding detected: logic_equal[context(Signer), identifier[${rc4_04_entry_identifier}]] where identifier[${rc4_04_entry_identifier}] is a fixed Address constant (${rc4_04_entry_detail}). Not wrapped in logic_or (not Level 2 identity-set).",
|
|
511
|
+
"stakeholders": ["provider"]
|
|
512
|
+
}
|
|
513
|
+
]
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
"rule_id": "R-X1-01",
|
|
517
|
+
"dimension": "logic_gap",
|
|
518
|
+
"trigger": "Time-lock uses logic_as_u256_greater_or_equal with a baseline query that has NO non-zero invariant (i.e. the query MAY legitimately return 0 when it succeeds), causing Clock >= 0 + timeout to always be true",
|
|
519
|
+
"cases": [
|
|
520
|
+
{
|
|
521
|
+
"when": { "field": "rx1_01_trigger", "op": "eq", "value": true },
|
|
522
|
+
"level": "medium",
|
|
523
|
+
"title": "Time-lock baseline query may return 0 causing >= comparison to always be true",
|
|
524
|
+
"description": "Guard uses logic_as_u256_greater_or_equal for time-lock comparison, and the compared baseline value comes from a query (Type1/2/3 data sources). If the query SUCCEEDS but its stored value is 0 (e.g. a count that is 0 in the empty initial state, a user-submitted value of 0, or a Some(0) from an Option field), then Clock >= 0 + timeout is always true, the time-lock is effectively void, and the disadvantaged party can bypass the time constraint immediately.\n\nIMPORTANT — 'VM error = Guard failure' baseline: if a query targets an absent object, unset Option, or missing collection entry, the WoWok native runtime aborts with a VM error (e.g. W_FIELD_NOT_FOUND) and the Guard fails as a whole (does NOT silently return 0). Therefore the null-bypass risk ONLY applies to queries whose stored value can legitimately be 0 while the query itself succeeds. Such queries are exactly those WITHOUT an `invariant` annotation in the SDK GUARDQUERY catalog.",
|
|
525
|
+
"scenario": "Time-lock invalidation: baseline query returns 0 (not VM error), making the >= condition always pass",
|
|
526
|
+
"mitigation": "1) Use a query whose return is guaranteed non-zero (look for `invariant` in guard-ins.ts — e.g. progress.current_time id=1272 with invariant='clock_derived'); 2) Add a precondition check query > 0 before the time-lock (for queries without an invariant, e.g. user-submitted baselines); 3) Avoid using count/index/find/user-submitted values as time-lock baselines — these can all legitimately return 0; 4) Distinguish 'VM error' (safe — Guard fails) from 'query returns 0' (unsafe — Guard bypassed). Only the latter is a null-bypass risk.",
|
|
527
|
+
"evidence": "${rx1_01_evidence}",
|
|
528
|
+
"stakeholders": ["customer", "provider"]
|
|
529
|
+
}
|
|
530
|
+
]
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"rule_id": "R-X1-02",
|
|
534
|
+
"dimension": "logic_gap",
|
|
535
|
+
"trigger": "Guard uses logic_as_u256_greater with a query operand that has NO non-zero invariant (i.e. the query MAY legitimately return 0 when it succeeds), and the comparison does not distinguish 'query succeeded with 0' from 'query failed'",
|
|
536
|
+
"cases": [
|
|
537
|
+
{
|
|
538
|
+
"when": { "field": "rx1_02_trigger", "op": "eq", "value": true },
|
|
539
|
+
"level": "medium",
|
|
540
|
+
"title": "Numeric comparison with a query that may legitimately return 0",
|
|
541
|
+
"description": "Guard uses logic_as_u256_greater for numeric comparison, and one of the operands comes from a query (Type1/2/3 data sources) that has NO non-zero invariant annotation. If the query SUCCEEDS but its stored value is 0 (e.g. a count that is 0 in the empty initial state, a user-submitted value of 0, or a Some(0) from an Option field), the comparison may produce an unexpected result (e.g. `query > 0` fails, or `query > some_threshold` is silently bypassed).\n\nIMPORTANT — 'VM error = Guard failure' baseline: if a query targets absent data (e.g. object does not exist, Option is None, collection entry is missing), the WoWok native runtime aborts with a VM error (not 0). The Guard fails as a whole (does NOT silently return 0). Therefore this rule only flags queries whose stored value can be 0 while the query succeeds.",
|
|
542
|
+
"scenario": "Null misjudgment: query succeeds with value 0, causing > 0 condition to unexpectedly fail (or > threshold to be bypassed)",
|
|
543
|
+
"mitigation": "1) Prefer queries with an `invariant` annotation (e.g. clock_derived / positive_lower_bound); 2) Add a precondition check (query > 0) before the main comparison when using count/index/find/user-submitted baselines; 3) Distinguish 'VM error' (safe — Guard fails) from 'query returns 0' (potentially unsafe). Only the latter is a null-bypass risk.",
|
|
544
|
+
"evidence": "${rx1_02_evidence}",
|
|
545
|
+
"stakeholders": ["customer", "provider"]
|
|
546
|
+
}
|
|
547
|
+
]
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
"rule_id": "R-X1-03",
|
|
551
|
+
"dimension": "logic_gap",
|
|
552
|
+
"trigger": "Guard uses logic_string_contains and may be bypassed by substring matching",
|
|
553
|
+
"cases": [
|
|
554
|
+
{
|
|
555
|
+
"when": { "all": [{ "field": "root_has_logic_string_contains", "op": "eq", "value": true }, { "field": "root_has_logic_string_nocase", "op": "eq", "value": false }] },
|
|
556
|
+
"level": "low",
|
|
557
|
+
"title": "logic_string_contains substring match may be bypassed",
|
|
558
|
+
"description": "Guard uses logic_string_contains for string matching.Substring matching may be bypassed: e.g. when checking 'Completed', 'NotCompleted' also contains 'Completed'.In addition, case sensitivity may cause unexpected failures. String data may come from Type1 (query object fields), Type3 (submitted values), or the context of a rely-dependent Guard.",
|
|
559
|
+
"scenario": "Substring mismatch: 'NotCompleted' contains 'Completed', causing false pass",
|
|
560
|
+
"mitigation": "1) Prefer logic_equal for exact matching;2) If substring matching is needed, add boundary conditions (e.g. prefix + suffix);3) Confirm whether case-insensitivity is needed (use the nocase variant)",
|
|
561
|
+
"stakeholders": ["customer", "provider"]
|
|
562
|
+
}
|
|
563
|
+
]
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
"rule_id": "R-X1-04",
|
|
567
|
+
"dimension": "logic_gap",
|
|
568
|
+
"trigger": "Guard root is an identifier directly returning Bool",
|
|
569
|
+
"cases": [
|
|
570
|
+
{
|
|
571
|
+
"when": { "all": [{ "field": "root_is_identifier", "op": "eq", "value": true }, { "field": "root_identifier_is_submission", "op": "eq", "value": true }] },
|
|
572
|
+
"level": "medium",
|
|
573
|
+
"title": "Root directly returns identifier value, no operation logic",
|
|
574
|
+
"description": "Guard root is an identifier node, directly returning the value (Bool) from table.This entry has b_submission=true (Type3 submitted value); the caller can directly submit true to bypass all verification.",
|
|
575
|
+
"scenario": "Bypass verification: caller submits true to pass the Guard directly",
|
|
576
|
+
"mitigation": "1) Ensure the entry referenced by identifier has b_submission=false (constant);2) Or add an additional logic_and condition for cross-validation",
|
|
577
|
+
"stakeholders": ["customer", "provider"]
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
"when": { "all": [{ "field": "root_is_identifier", "op": "eq", "value": true }, { "field": "root_identifier_is_submission", "op": "eq", "value": false }] },
|
|
581
|
+
"level": "low",
|
|
582
|
+
"title": "Root directly returns identifier value, no operation logic",
|
|
583
|
+
"description": "Guard root is an identifier node, directly returning the value (Bool) from table.This entry has b_submission=false (Type1 constant); the value is fixed but the Guard has no actual verification logic.",
|
|
584
|
+
"scenario": "No verification logic: Guard always returns a fixed value, providing no actual protection",
|
|
585
|
+
"mitigation": "1) Add actual verification logic (query + logic comparison);2) Evaluate whether this Guard needs to exist",
|
|
586
|
+
"stakeholders": ["customer", "provider"]
|
|
587
|
+
}
|
|
588
|
+
]
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"rule_id": "R-X1-05",
|
|
592
|
+
"dimension": "game_theory",
|
|
593
|
+
"trigger": "Allocation Guard may cause some participants to be skipped",
|
|
594
|
+
"cases": [
|
|
595
|
+
{
|
|
596
|
+
"when": { "field": "scene_binding_field", "op": "eq", "value": "order_allocators" },
|
|
597
|
+
"level": "medium",
|
|
598
|
+
"title": "order_allocators first-match-wins may cause unfair allocation",
|
|
599
|
+
"description": "order_allocators uses a first-match-wins strategy: the first Allocator whose Guard passes executes the allocation.If the order is poorly designed, some participants may never get allocated.For example: if the first Allocator's Guard condition is too broad, subsequent more precise Allocators will never execute.Allocation Guards typically combine Type1 (query order fields), Type3 (submit Order address), and Type4 (Signer) data.",
|
|
600
|
+
"scenario": "Allocation skip: the Provider's allocation Allocator is skipped by preceding broad conditions",
|
|
601
|
+
"mitigation": "1) Ensure the order_allocators order goes from strict to loose;2) Each Allocator's Guard conditions should be mutually exclusive;3) Consider using logic_or dependencies rather than sequential ordering",
|
|
602
|
+
"stakeholders": ["provider"]
|
|
603
|
+
}
|
|
604
|
+
]
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
"rule_id": "R-X1-06",
|
|
608
|
+
"dimension": "game_theory",
|
|
609
|
+
"trigger": "Workflow Guard time-lock may lock the disadvantaged party",
|
|
610
|
+
"cases": [
|
|
611
|
+
{
|
|
612
|
+
"when": { "all": [{ "field": "root_has_clock_token", "op": "eq", "value": true }, { "field": "root_has_calc_number_add", "op": "eq", "value": true }] },
|
|
613
|
+
"level": "medium",
|
|
614
|
+
"title": "Time-lock may lock the disadvantaged party",
|
|
615
|
+
"description": "Guard uses a time-lock (context(Clock) + calc_number_add). The time-lock itself is neutral, but the locking direction needs to be checked: if the Customer is locked to pay first but cannot accept in time, the Provider gains advantage; if the Provider is locked to deliver first but cannot receive payment in time, the Customer gains advantage.The time-lock combines Type4 (Clock) and Type1/2 (query time fields) data sources.",
|
|
616
|
+
"scenario": "Time asymmetry: one party is locked by time while the other has freedom of action",
|
|
617
|
+
"mitigation": "1) Ensure the time-lock is symmetric (both parties have time constraints);2) Provide an exit mechanism after the time-lock expires (e.g. auto-refund/auto-complete);3) Design corresponding timeout Forward nodes in the Machine",
|
|
618
|
+
"stakeholders": ["customer", "provider"]
|
|
619
|
+
}
|
|
620
|
+
]
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
"rule_id": "R-X1-07",
|
|
624
|
+
"dimension": "game_theory",
|
|
625
|
+
"trigger": "Arbitration usage_guard may block legitimate disputes",
|
|
626
|
+
"cases": [
|
|
627
|
+
{
|
|
628
|
+
"when": { "all": [{ "field": "scene_binding_field", "op": "eq", "value": "usage_guard" }, { "field": "logic_and_count", "op": "gte", "value": 3 }] },
|
|
629
|
+
"level": "high",
|
|
630
|
+
"title": "usage_guard has too many conditions and may block legitimate disputes",
|
|
631
|
+
"description": "Detected ${logic_and_count} logic_and combinations. Too many AND conditions make the dispute threshold too high, the Customer may not be able to initiate a legitimate dispute, and the Provider gains an unfair advantage.usage_guard typically combines Type4 (Signer identity), Type3 (submit Passport credentials), and Type1 (query EntityRegistrar verification) data sources.",
|
|
632
|
+
"scenario": "Dispute threshold too high: Customer cannot initiate a legitimate dispute",
|
|
633
|
+
"mitigation": "1) Re-evaluate the necessity of each AND condition;2) Consider using logic_or to lower the threshold;3) Move non-essential conditions to voting_guard rather than usage_guard",
|
|
634
|
+
"stakeholders": ["customer"],
|
|
635
|
+
"exposure": {
|
|
636
|
+
"loss_parties": [
|
|
637
|
+
{ "role": "buyer", "basis": "The dispute entry threshold is stacked so high that a legitimate dispute cannot be initiated — the buyer's compensation path becomes inaccessible." }
|
|
638
|
+
],
|
|
639
|
+
"gain_paths": []
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
]
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
"rule_id": "R-X1-08",
|
|
646
|
+
"dimension": "binding_risk",
|
|
647
|
+
"trigger": "Guard is bound to a published Machine/Service (immutable)",
|
|
648
|
+
"cases": [
|
|
649
|
+
{
|
|
650
|
+
"when": { "all": [{ "field": "scene_present", "op": "eq", "value": true }, { "field": "scene_mutable_after_publish", "op": "falsy" }] },
|
|
651
|
+
"level": "low",
|
|
652
|
+
"title": "Guard is bound to immutable ${scene_host_object} (cannot be modified after publish)",
|
|
653
|
+
"description": "After ${scene_host_object} is published, ${scene_binding_field} cannot be modified.If the Guard design is flawed, a new Machine/Service must be created and all references migrated.This is a design constraint rather than a risk, but the Guard design must be correct before publishing.",
|
|
654
|
+
"scenario": "Irreversible binding: after publish, a flawed Guard design cannot be modified",
|
|
655
|
+
"mitigation": "1) Use gen_passport for thorough testing before publishing;2) Test both expected-pass and expected-fail scenarios;3) Export a Guard backup (guard2file) before publishing",
|
|
656
|
+
"stakeholders": ["provider"]
|
|
657
|
+
}
|
|
658
|
+
]
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
"rule_id": "R-X1-09",
|
|
662
|
+
"dimension": "dependency_risk",
|
|
663
|
+
"trigger": "Guard uses rely but the dependent Guard may fail",
|
|
664
|
+
"cases": [
|
|
665
|
+
{
|
|
666
|
+
"when": { "all": [{ "field": "rely_guards_count", "op": "gt", "value": 0 }, { "field": "rely_is_or", "op": "eq", "value": true }] },
|
|
667
|
+
"level": "low",
|
|
668
|
+
"title": "rely ${rely_logic} depends on ${rely_guards_count} external Guards",
|
|
669
|
+
"description": "Guard uses rely ${rely_logic} to depend on ${rely_guards_count} external Guards.OR logic: any one passing is enough. If a dependent Guard is loosely designed, it may become a bypass entry point. rely-dependent Guards must have rep=true (repository.data queries do not depend on runtime submission).",
|
|
670
|
+
"scenario": "Dependency bypass: a loose dependent Guard becomes an attack entry point",
|
|
671
|
+
"mitigation": "1) Review the strictness of each dependent Guard; 2) Ensure all dependent Guards are at least as strict as the current Guard",
|
|
672
|
+
"stakeholders": ["customer", "provider"]
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"when": { "all": [{ "field": "rely_guards_count", "op": "gt", "value": 0 }, { "field": "rely_is_or", "op": "eq", "value": false }] },
|
|
676
|
+
"level": "medium",
|
|
677
|
+
"title": "rely ${rely_logic} depends on ${rely_guards_count} external Guards",
|
|
678
|
+
"description": "Guard uses rely ${rely_logic} to depend on ${rely_guards_count} external Guards.AND logic: all dependencies must pass. If a dependent Guard fails or is deleted, the current Guard will always fail. rely-dependent Guards must have rep=true (repository.data queries do not depend on runtime submission).",
|
|
679
|
+
"scenario": "Dependency failure: a dependent Guard is deleted, causing the current Guard to always fail",
|
|
680
|
+
"mitigation": "1) Confirm all dependent Guards have rep=true and cannot be deleted; 2) Consider whether AND dependency is truly needed",
|
|
681
|
+
"stakeholders": ["customer", "provider"]
|
|
682
|
+
}
|
|
683
|
+
]
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"rule_id": "R-X1-10",
|
|
687
|
+
"dimension": "impack_risk",
|
|
688
|
+
"trigger": "Guard uses repository.data query (query 1167) and the Repository has quote_guard set — rigid verification requirement",
|
|
689
|
+
"cases": [
|
|
690
|
+
{
|
|
691
|
+
"when": { "all": [{ "field": "queries_repository", "op": "eq", "value": true }, { "field": "root_has_query", "op": "eq", "value": true }] },
|
|
692
|
+
"level": "low",
|
|
693
|
+
"title": "repository.data quote_guard is a RIGID verification requirement (data subscription access control)",
|
|
694
|
+
"description": "When a Guard queries repository.data (query 1167), if the Repository policy has quote_guard set (Some(addr)), then the quote_guard MUST be verified. This is a RIGID requirement — not context-dependent.\n\nTWO-PHASE VERIFICATION MECHANISM (VERIFIED: passport.rs#L756-769, passport.rs#L545-612):\n Phase 1 — Passport generation (scan guard): The system scans the Guard to identify that it queries repository data. If the Repository has a quote_guard, the system prepares the quote_guard for verification (adds it to the required verification set, populating impack_list).\n Phase 2 — Passport verification: The system re-checks (a) is the quote_guard prepared/in impack_list? (b) rigidly verify the quote_guard (e.g., verify Payment proof for subscription).\n\nSEMANTIC INTENT: Any Guard that uses a Repository's data MUST satisfy that Repository's quote_guard. This is the intended access control mechanism for data subscription — e.g., accessing weather data requires payment proof verified by the quote_guard.\n\nDESIGN PHILOSOPHY: On-chain data is consumed by guard verifiers. The quote_guard gates Repository data access, enabling subscription revenue models. The Guard only verifies logic + data accuracy (verifier-evidence design).",
|
|
695
|
+
"scenario": "quote_guard rigid verification: any guard querying repository data must satisfy the repository's quote_guard (e.g., payment requirement)",
|
|
696
|
+
"mitigation": "1) This is an INTENDED capability, not a limitation — quote_guard enables data subscription access control;\n2) When designing a Guard that queries Repository data with quote_guard: ensure the Passport includes the quote_guard verification with necessary submissions (e.g., Payment proof);\n3) Pattern: Repository with quote_guard for data subscription — quote_guard verifies Payment (for_object, for_guard, index), user submits Payment via Passport, quote_guard verified in both phases, repository data query passes;\n4) If quote_guard==None: no access control — Repository data is freely queryable",
|
|
697
|
+
"stakeholders": ["customer", "provider"]
|
|
698
|
+
}
|
|
699
|
+
]
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
"rule_id": "R-X1-11",
|
|
703
|
+
"dimension": "rep_risk",
|
|
704
|
+
"trigger": "Guard uses rely to depend on other Guards; need to confirm the rep flag of dependent Guards is correct",
|
|
705
|
+
"cases": [
|
|
706
|
+
{
|
|
707
|
+
"when": { "all": [{ "field": "rely_guards_count", "op": "gt", "value": 0 }, { "field": "rx1_11_self_rep_false", "op": "eq", "value": true }] },
|
|
708
|
+
"level": "medium",
|
|
709
|
+
"title": "rep semantics needs confirmation (when repository.data query depends on submission, rep=false and cannot be depended on)",
|
|
710
|
+
"description": "Guard uses rely to depend on external Guards. In the WoWok protocol, rely-dependent Guards must have rep=true.\nPrecise rep semantics (guard.rs#L483-L492): repository.data query (query 1167) does not depend on runtime submission.\n - rep=true: repository.data query is fully constant-driven (object address b_submission=false and query parameters are not submission)\n - rep=false: repository address comes from runtime submission, or query parameters come from submission\nGuards with rep=false cannot appear in other Guards' rely lists.\n${rx1_11_warning_tail}",
|
|
711
|
+
"scenario": "rep misjudgment: depending on a rep=false Guard causes creation failure, or its own rep=false is wrongly depended on",
|
|
712
|
+
"mitigation": "1) Confirm all rely-dependent Guards have rep=true (do not depend on submission to query repository.data);2) If the current Guard queries repository.data and the address comes from submission, its own rep=false; annotate that it cannot be depended on;3) rep is not 'no Repository dependency', but 'repository.data query does not depend on submission';4) Use wowok_buildin_info to query the full definition of the rep flag",
|
|
713
|
+
"evidence": "${rx1_11_evidence}",
|
|
714
|
+
"stakeholders": ["provider"]
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
"when": { "all": [{ "field": "rely_guards_count", "op": "gt", "value": 0 }, { "field": "rx1_11_self_rep_false", "op": "eq", "value": false }] },
|
|
718
|
+
"level": "low",
|
|
719
|
+
"title": "rep semantics needs confirmation (when repository.data query depends on submission, rep=false and cannot be depended on)",
|
|
720
|
+
"description": "Guard uses rely to depend on external Guards. In the WoWok protocol, rely-dependent Guards must have rep=true.\nPrecise rep semantics (guard.rs#L483-L492): repository.data query (query 1167) does not depend on runtime submission.\n - rep=true: repository.data query is fully constant-driven (object address b_submission=false and query parameters are not submission)\n - rep=false: repository address comes from runtime submission, or query parameters come from submission\nGuards with rep=false cannot appear in other Guards' rely lists.\n${rx1_11_warning_tail}",
|
|
721
|
+
"scenario": "rep misjudgment: depending on a rep=false Guard causes creation failure, or its own rep=false is wrongly depended on",
|
|
722
|
+
"mitigation": "1) Confirm all rely-dependent Guards have rep=true (do not depend on submission to query repository.data);2) If the current Guard queries repository.data and the address comes from submission, its own rep=false; annotate that it cannot be depended on;3) rep is not 'no Repository dependency', but 'repository.data query does not depend on submission';4) Use wowok_buildin_info to query the full definition of the rep flag",
|
|
723
|
+
"evidence": "${rx1_11_evidence}",
|
|
724
|
+
"stakeholders": ["provider"]
|
|
725
|
+
}
|
|
726
|
+
]
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"rule_id": "R-X1-12",
|
|
730
|
+
"dimension": "submission_forgery",
|
|
731
|
+
"trigger": "Guard table contains b_submission=true entries with vague name descriptions or missing binding_constraint",
|
|
732
|
+
"cases": [
|
|
733
|
+
{
|
|
734
|
+
"when": { "field": "rx1_12_vague_count", "op": "gt", "value": 0 },
|
|
735
|
+
"level": "medium",
|
|
736
|
+
"title": "Submitted data entry description is vague (retained_submission risk: caller may submit wrong data)",
|
|
737
|
+
"description": "Guard table has ${rx1_12_vague_count} b_submission=true entries with vague name descriptions.\nThe name of a submission entry is the only data contract between the Guard and the caller.\nIf the name description is unclear (e.g. only 'addr' / 'order_id'), the caller may:\n - Submit a wrong-typed object address (e.g. submit a Service address instead of an Order address)\n - Submit a wrong value (e.g. inconsistent amount units)\n - Confuse submission slots of different Guards in multi-Guard scenarios\nVague submission entries are 'retained' in the table but provide no effective data constraints, equivalent to the Guard accepting arbitrary data without validating its semantic correctness.",
|
|
738
|
+
"scenario": "Caller submits wrong data due to vague name description; the Guard passes verification but the business logic is wrong",
|
|
739
|
+
"mitigation": "1) Each submission entry's name should be a complete natural-language description (e.g. 'The order ID that identifies the target Order for verification');\n2) Avoid Technical identifiers as name (e.g. 'order_id' should become 'Order ID, used to query progress status');\n3) Add failure_conditions in binding_hint to clarify failure scenarios;\n4) Consider adding type validation logic in root (e.g. query the submitted object's objectType and match with expectation)",
|
|
740
|
+
"evidence": "Vague entries: ${rx1_12_vague_csv}",
|
|
741
|
+
"stakeholders": ["customer", "provider"]
|
|
742
|
+
}
|
|
743
|
+
]
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"rule_id": "R-X1-13",
|
|
747
|
+
"dimension": "binding_risk",
|
|
748
|
+
"trigger": "Guard references its host object (Host Object) itself — circular reference pattern",
|
|
749
|
+
"cases": [
|
|
750
|
+
{
|
|
751
|
+
"when": { "field": "rx1_13_detected", "op": "eq", "value": true },
|
|
752
|
+
"level": "medium",
|
|
753
|
+
"title": "Circular reference pattern (Guard references the host object itself; note creation order)",
|
|
754
|
+
"description": "In the Guard's table, identifier=${rx1_13_identifier} has object_type equal to the host object type \"${scene_host_object}\".\nCircular reference pattern: the Guard is bound to a Host Object (e.g. Service.buy_guard) and also queries the Host Object's own fields.\nCreation order constraints:\n 1. The Host Object must be created first (unpublished state)\n 2. When the Guard is created, the table uses the Host Object's name (not address); the SDK resolves it at binding time\n 3. After the Guard is bound to the Host Object, the Host Object is published\nRisks:\n - If the Host Object is already published (immutable), the Guard can no longer be bound\n - If the Host Object's name is modified after the Guard is created, the Guard's table reference is invalidated\n - Circular reference makes the Guard not independently testable (the Host Object must exist to verify)",
|
|
755
|
+
"scenario": "Guard queries fields of the Service/Machine/Reward it is bound to; wrong creation order causes binding failure",
|
|
756
|
+
"mitigation": "1) Ensure the Host Object is unpublished (bPublished=false) when creating and binding the Guard;\n2) Use the Host Object's name rather than address in table (the SDK auto-resolves);\n3) Perform Guard verification tests after the Host Object is published;\n4) Use guard2file to export a Guard backup for restoring references during rebuild",
|
|
757
|
+
"evidence": "Circular reference: identifier=${rx1_13_identifier}, object_type=\"${scene_host_object}\" → ${scene_host_object}",
|
|
758
|
+
"stakeholders": ["provider"]
|
|
759
|
+
}
|
|
760
|
+
]
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
"rule_id": "R-X1-14",
|
|
764
|
+
"dimension": "logic_gap",
|
|
765
|
+
"trigger": "Scene-specific reentrancy: Guard pass triggers a state-changing side effect (fund distribution, vote count, Arb creation) that does NOT naturally invalidate the Guard condition. Without an anti-reentrancy primitive, the same Signer can repeatedly pass the Guard. Additionally detects pseudo-protection: primitive present but not properly wrapped in logic_not (for Bool queries) or logic_equal(0) (for count queries).",
|
|
766
|
+
"cases": [
|
|
767
|
+
{
|
|
768
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "pseudo" }, { "field": "reentry_scene_id", "op": "eq", "value": "reward_claim" }] },
|
|
769
|
+
"level": "medium",
|
|
770
|
+
"title": "Reentrancy pseudo-protection: anti-reentrancy primitive present but not properly wrapped (${reentry_scene_id})",
|
|
771
|
+
"description": "Scene: ${reentry_scene_id}\nThe Guard root contains an anti-reentrancy primitive (${reentry_found_primitive}), but it is NOT properly wrapped.\nProper wrapping rules:\n - Bool-returning primitives (exists-style): must be wrapped in logic_not\n - U64-returning primitives (count-style): must be compared to 0 via logic_equal\n - Address-returning primitives: must be wrapped in logic_not (None check)\n\nWHY THIS IS DANGEROUS:\n The developer likely intended to prevent reentrancy but the wrapping is incorrect, so the primitive does NOT actually block repeated Guard passes. This is arguably MORE dangerous than absence — code reviewers see the primitive and assume protection is in place.\n\nScene rationale: ${reentry_rationale}",
|
|
772
|
+
"scenario": "Developer added anti-reentrancy primitive but used wrong wrapping; reentrancy exploit still possible in ${reentry_scene_id}",
|
|
773
|
+
"mitigation": "Fix the wrapping:\n - For exists-style (Bool) primitives: wrap in logic_not — { type: 'logic_not', node: { type: 'query', query: <primitive>, ... } }\n - For count-style (U64) primitives: compare to 0 — { type: 'logic_equal', nodes: [ { type: 'query', query: <primitive>, ... }, identifier(N) ] } where table[N].value = 0\n - For address-style primitives: wrap in logic_not (None check)\nThen wrap the protection in logic_and with the existing root conditions.\n\nFull mitigation for ${reentry_scene_id}:\n${reentry_mitigation}",
|
|
774
|
+
"evidence": "${reentry_evidence}",
|
|
775
|
+
"stakeholders": ["claimant", "provider"],
|
|
776
|
+
"exposure": {
|
|
777
|
+
"loss_parties": [
|
|
778
|
+
{ "role": "merchant", "basis": "The reward pool is the merchant's deposited budget — repeated Guard passes let the same signer drain it multiple times." }
|
|
779
|
+
],
|
|
780
|
+
"gain_paths": [
|
|
781
|
+
{
|
|
782
|
+
"role": "neutral",
|
|
783
|
+
"path": "The same signer repeatedly passes the claim Guard and collects the payout again each time.",
|
|
784
|
+
"viability": "viable",
|
|
785
|
+
"gate": "The anti-reentrancy primitive is absent or mis-wrapped, so no on-chain check blocks the repeat pass."
|
|
786
|
+
}
|
|
787
|
+
]
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "pseudo" }, { "field": "reentry_scene_id", "op": "eq", "value": "arbitration_voting_guard" }] },
|
|
792
|
+
"level": "medium",
|
|
793
|
+
"title": "Reentrancy pseudo-protection: anti-reentrancy primitive present but not properly wrapped (${reentry_scene_id})",
|
|
794
|
+
"description": "Scene: ${reentry_scene_id}\nThe Guard root contains an anti-reentrancy primitive (${reentry_found_primitive}), but it is NOT properly wrapped.\nProper wrapping rules:\n - Bool-returning primitives (exists-style): must be wrapped in logic_not\n - U64-returning primitives (count-style): must be compared to 0 via logic_equal\n - Address-returning primitives: must be wrapped in logic_not (None check)\n\nWHY THIS IS DANGEROUS:\n The developer likely intended to prevent reentrancy but the wrapping is incorrect, so the primitive does NOT actually block repeated Guard passes. This is arguably MORE dangerous than absence — code reviewers see the primitive and assume protection is in place.\n\nScene rationale: ${reentry_rationale}",
|
|
795
|
+
"scenario": "Developer added anti-reentrancy primitive but used wrong wrapping; reentrancy exploit still possible in ${reentry_scene_id}",
|
|
796
|
+
"mitigation": "Fix the wrapping:\n - For exists-style (Bool) primitives: wrap in logic_not — { type: 'logic_not', node: { type: 'query', query: <primitive>, ... } }\n - For count-style (U64) primitives: compare to 0 — { type: 'logic_equal', nodes: [ { type: 'query', query: <primitive>, ... }, identifier(N) ] } where table[N].value = 0\n - For address-style primitives: wrap in logic_not (None check)\nThen wrap the protection in logic_and with the existing root conditions.\n\nFull mitigation for ${reentry_scene_id}:\n${reentry_mitigation}",
|
|
797
|
+
"evidence": "${reentry_evidence}",
|
|
798
|
+
"stakeholders": ["customer", "provider", "arbitrator"],
|
|
799
|
+
"exposure": {
|
|
800
|
+
"loss_parties": [
|
|
801
|
+
{ "role": "buyer", "basis": "Repeated vote counting can swing the arbitration ruling — the buyer may be denied a deserved payout or charged a wrongful one." },
|
|
802
|
+
{ "role": "merchant", "basis": "The same manipulated ruling can force an unjustified compensation payout from the merchant side." }
|
|
803
|
+
],
|
|
804
|
+
"gain_paths": [
|
|
805
|
+
{
|
|
806
|
+
"role": "neutral",
|
|
807
|
+
"path": "The same signer repeatedly passes the voting Guard, re-triggering the vote-count side effect until the tally favors them.",
|
|
808
|
+
"viability": "viable",
|
|
809
|
+
"gate": "The anti-reentrancy primitive is absent or mis-wrapped, so no on-chain check blocks the repeat pass."
|
|
810
|
+
}
|
|
811
|
+
]
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "pseudo" }, { "field": "reentry_scene_id", "op": "eq", "value": "arbitration_usage_guard" }] },
|
|
816
|
+
"level": "medium",
|
|
817
|
+
"title": "Reentrancy pseudo-protection: anti-reentrancy primitive present but not properly wrapped (${reentry_scene_id})",
|
|
818
|
+
"description": "Scene: ${reentry_scene_id}\nThe Guard root contains an anti-reentrancy primitive (${reentry_found_primitive}), but it is NOT properly wrapped.\nProper wrapping rules:\n - Bool-returning primitives (exists-style): must be wrapped in logic_not\n - U64-returning primitives (count-style): must be compared to 0 via logic_equal\n - Address-returning primitives: must be wrapped in logic_not (None check)\n\nWHY THIS IS DANGEROUS:\n The developer likely intended to prevent reentrancy but the wrapping is incorrect, so the primitive does NOT actually block repeated Guard passes. This is arguably MORE dangerous than absence — code reviewers see the primitive and assume protection is in place.\n\nScene rationale: ${reentry_rationale}",
|
|
819
|
+
"scenario": "Developer added anti-reentrancy primitive but used wrong wrapping; reentrancy exploit still possible in ${reentry_scene_id}",
|
|
820
|
+
"mitigation": "Fix the wrapping:\n - For exists-style (Bool) primitives: wrap in logic_not — { type: 'logic_not', node: { type: 'query', query: <primitive>, ... } }\n - For count-style (U64) primitives: compare to 0 — { type: 'logic_equal', nodes: [ { type: 'query', query: <primitive>, ... }, identifier(N) ] } where table[N].value = 0\n - For address-style primitives: wrap in logic_not (None check)\nThen wrap the protection in logic_and with the existing root conditions.\n\nFull mitigation for ${reentry_scene_id}:\n${reentry_mitigation}",
|
|
821
|
+
"evidence": "${reentry_evidence}",
|
|
822
|
+
"stakeholders": ["customer", "provider"]
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "pseudo" }, { "field": "reentry_scene_id", "op": "eq", "value": "service_order_allocators_guard" }] },
|
|
826
|
+
"level": "medium",
|
|
827
|
+
"title": "Reentrancy pseudo-protection: anti-reentrancy primitive present but not properly wrapped (${reentry_scene_id})",
|
|
828
|
+
"description": "Scene: ${reentry_scene_id}\nThe Guard root contains an anti-reentrancy primitive (${reentry_found_primitive}), but it is NOT properly wrapped.\nProper wrapping rules:\n - Bool-returning primitives (exists-style): must be wrapped in logic_not\n - U64-returning primitives (count-style): must be compared to 0 via logic_equal\n - Address-returning primitives: must be wrapped in logic_not (None check)\n\nWHY THIS IS DANGEROUS:\n The developer likely intended to prevent reentrancy but the wrapping is incorrect, so the primitive does NOT actually block repeated Guard passes. This is arguably MORE dangerous than absence — code reviewers see the primitive and assume protection is in place.\n\nScene rationale: ${reentry_rationale}",
|
|
829
|
+
"scenario": "Developer added anti-reentrancy primitive but used wrong wrapping; reentrancy exploit still possible in ${reentry_scene_id}",
|
|
830
|
+
"mitigation": "Fix the wrapping:\n - For exists-style (Bool) primitives: wrap in logic_not — { type: 'logic_not', node: { type: 'query', query: <primitive>, ... } }\n - For count-style (U64) primitives: compare to 0 — { type: 'logic_equal', nodes: [ { type: 'query', query: <primitive>, ... }, identifier(N) ] } where table[N].value = 0\n - For address-style primitives: wrap in logic_not (None check)\nThen wrap the protection in logic_and with the existing root conditions.\n\nFull mitigation for ${reentry_scene_id}:\n${reentry_mitigation}",
|
|
831
|
+
"evidence": "${reentry_evidence}",
|
|
832
|
+
"stakeholders": ["customer", "provider"]
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "pseudo" }, { "field": "reentry_scene_id", "op": "eq", "value": "service_buy_guard" }] },
|
|
836
|
+
"level": "medium",
|
|
837
|
+
"title": "Reentrancy pseudo-protection: anti-reentrancy primitive present but not properly wrapped (${reentry_scene_id})",
|
|
838
|
+
"description": "Scene: ${reentry_scene_id}\nThe Guard root contains an anti-reentrancy primitive (${reentry_found_primitive}), but it is NOT properly wrapped.\nProper wrapping rules:\n - Bool-returning primitives (exists-style): must be wrapped in logic_not\n - U64-returning primitives (count-style): must be compared to 0 via logic_equal\n - Address-returning primitives: must be wrapped in logic_not (None check)\n\nWHY THIS IS DANGEROUS:\n The developer likely intended to prevent reentrancy but the wrapping is incorrect, so the primitive does NOT actually block repeated Guard passes. This is arguably MORE dangerous than absence — code reviewers see the primitive and assume protection is in place.\n\nScene rationale: ${reentry_rationale}",
|
|
839
|
+
"scenario": "Developer added anti-reentrancy primitive but used wrong wrapping; reentrancy exploit still possible in ${reentry_scene_id}",
|
|
840
|
+
"mitigation": "Fix the wrapping:\n - For exists-style (Bool) primitives: wrap in logic_not — { type: 'logic_not', node: { type: 'query', query: <primitive>, ... } }\n - For count-style (U64) primitives: compare to 0 — { type: 'logic_equal', nodes: [ { type: 'query', query: <primitive>, ... }, identifier(N) ] } where table[N].value = 0\n - For address-style primitives: wrap in logic_not (None check)\nThen wrap the protection in logic_and with the existing root conditions.\n\nFull mitigation for ${reentry_scene_id}:\n${reentry_mitigation}",
|
|
841
|
+
"evidence": "${reentry_evidence}",
|
|
842
|
+
"stakeholders": ["provider"]
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "pseudo" }, { "field": "reentry_scene_id", "op": "eq", "value": "repository_write_guard" }] },
|
|
846
|
+
"level": "medium",
|
|
847
|
+
"title": "Reentrancy pseudo-protection: anti-reentrancy primitive present but not properly wrapped (${reentry_scene_id})",
|
|
848
|
+
"description": "Scene: ${reentry_scene_id}\nThe Guard root contains an anti-reentrancy primitive (${reentry_found_primitive}), but it is NOT properly wrapped.\nProper wrapping rules:\n - Bool-returning primitives (exists-style): must be wrapped in logic_not\n - U64-returning primitives (count-style): must be compared to 0 via logic_equal\n - Address-returning primitives: must be wrapped in logic_not (None check)\n\nWHY THIS IS DANGEROUS:\n The developer likely intended to prevent reentrancy but the wrapping is incorrect, so the primitive does NOT actually block repeated Guard passes. This is arguably MORE dangerous than absence — code reviewers see the primitive and assume protection is in place.\n\nScene rationale: ${reentry_rationale}",
|
|
849
|
+
"scenario": "Developer added anti-reentrancy primitive but used wrong wrapping; reentrancy exploit still possible in ${reentry_scene_id}",
|
|
850
|
+
"mitigation": "Fix the wrapping:\n - For exists-style (Bool) primitives: wrap in logic_not — { type: 'logic_not', node: { type: 'query', query: <primitive>, ... } }\n - For count-style (U64) primitives: compare to 0 — { type: 'logic_equal', nodes: [ { type: 'query', query: <primitive>, ... }, identifier(N) ] } where table[N].value = 0\n - For address-style primitives: wrap in logic_not (None check)\nThen wrap the protection in logic_and with the existing root conditions.\n\nFull mitigation for ${reentry_scene_id}:\n${reentry_mitigation}",
|
|
851
|
+
"evidence": "${reentry_evidence}",
|
|
852
|
+
"stakeholders": ["provider"]
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "pseudo" }, { "field": "reentry_scene_id", "op": "eq", "value": "gen_passport_guard" }] },
|
|
856
|
+
"level": "medium",
|
|
857
|
+
"title": "Reentrancy pseudo-protection: anti-reentrancy primitive present but not properly wrapped (${reentry_scene_id})",
|
|
858
|
+
"description": "Scene: ${reentry_scene_id}\nThe Guard root contains an anti-reentrancy primitive (${reentry_found_primitive}), but it is NOT properly wrapped.\nProper wrapping rules:\n - Bool-returning primitives (exists-style): must be wrapped in logic_not\n - U64-returning primitives (count-style): must be compared to 0 via logic_equal\n - Address-returning primitives: must be wrapped in logic_not (None check)\n\nWHY THIS IS DANGEROUS:\n The developer likely intended to prevent reentrancy but the wrapping is incorrect, so the primitive does NOT actually block repeated Guard passes. This is arguably MORE dangerous than absence — code reviewers see the primitive and assume protection is in place.\n\nScene rationale: ${reentry_rationale}",
|
|
859
|
+
"scenario": "Developer added anti-reentrancy primitive but used wrong wrapping; reentrancy exploit still possible in ${reentry_scene_id}",
|
|
860
|
+
"mitigation": "Fix the wrapping:\n - For exists-style (Bool) primitives: wrap in logic_not — { type: 'logic_not', node: { type: 'query', query: <primitive>, ... } }\n - For count-style (U64) primitives: compare to 0 — { type: 'logic_equal', nodes: [ { type: 'query', query: <primitive>, ... }, identifier(N) ] } where table[N].value = 0\n - For address-style primitives: wrap in logic_not (None check)\nThen wrap the protection in logic_and with the existing root conditions.\n\nFull mitigation for ${reentry_scene_id}:\n${reentry_mitigation}",
|
|
861
|
+
"evidence": "${reentry_evidence}",
|
|
862
|
+
"stakeholders": ["provider"]
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "absent" }, { "field": "reentry_scene_id", "op": "eq", "value": "reward_claim" }] },
|
|
866
|
+
"level": "critical",
|
|
867
|
+
"title": "Reentrancy risk: ${reentry_scene_id} has NO anti-reentrancy protection (CRITICAL)",
|
|
868
|
+
"description": "Scene: ${reentry_scene_id}\nReentrancy risk level: CRITICAL\n\nRATIONALE:\n${reentry_rationale}\n\nDETECTION:\n${reentry_evidence}\n\nIMPACT: Without protection, the same Signer can repeatedly trigger the side effect (fund distribution / vote counting), causing direct fund loss or result manipulation. THIS IS A CRITICAL VULNERABILITY — the Guard MUST be rebuilt with an anti-reentrancy primitive before deployment.\n\n",
|
|
869
|
+
"scenario": "${reentry_scene_id} lacks anti-reentrancy primitive; same Signer can repeatedly trigger the side effect",
|
|
870
|
+
"mitigation": "${reentry_mitigation}",
|
|
871
|
+
"evidence": "${reentry_evidence}",
|
|
872
|
+
"stakeholders": ["claimant", "provider"],
|
|
873
|
+
"exposure": {
|
|
874
|
+
"loss_parties": [
|
|
875
|
+
{ "role": "merchant", "basis": "The reward pool is the merchant's deposited budget — repeated Guard passes let the same signer drain it multiple times." }
|
|
876
|
+
],
|
|
877
|
+
"gain_paths": [
|
|
878
|
+
{
|
|
879
|
+
"role": "neutral",
|
|
880
|
+
"path": "The same signer repeatedly passes the claim Guard and collects the payout again each time.",
|
|
881
|
+
"viability": "viable",
|
|
882
|
+
"gate": "The anti-reentrancy primitive is absent or mis-wrapped, so no on-chain check blocks the repeat pass."
|
|
883
|
+
}
|
|
884
|
+
]
|
|
885
|
+
}
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "absent" }, { "field": "reentry_scene_id", "op": "eq", "value": "arbitration_voting_guard" }] },
|
|
889
|
+
"level": "critical",
|
|
890
|
+
"title": "Reentrancy risk: ${reentry_scene_id} has NO anti-reentrancy protection (CRITICAL)",
|
|
891
|
+
"description": "Scene: ${reentry_scene_id}\nReentrancy risk level: CRITICAL\n\nRATIONALE:\n${reentry_rationale}\n\nDETECTION:\n${reentry_evidence}\n\nIMPACT: Without protection, the same Signer can repeatedly trigger the side effect (fund distribution / vote counting), causing direct fund loss or result manipulation. THIS IS A CRITICAL VULNERABILITY — the Guard MUST be rebuilt with an anti-reentrancy primitive before deployment.\n\n",
|
|
892
|
+
"scenario": "${reentry_scene_id} lacks anti-reentrancy primitive; same Signer can repeatedly trigger the side effect",
|
|
893
|
+
"mitigation": "${reentry_mitigation}",
|
|
894
|
+
"evidence": "${reentry_evidence}",
|
|
895
|
+
"stakeholders": ["customer", "provider", "arbitrator"],
|
|
896
|
+
"exposure": {
|
|
897
|
+
"loss_parties": [
|
|
898
|
+
{ "role": "buyer", "basis": "Repeated vote counting can swing the arbitration ruling — the buyer may be denied a deserved payout or charged a wrongful one." },
|
|
899
|
+
{ "role": "merchant", "basis": "The same manipulated ruling can force an unjustified compensation payout from the merchant side." }
|
|
900
|
+
],
|
|
901
|
+
"gain_paths": [
|
|
902
|
+
{
|
|
903
|
+
"role": "neutral",
|
|
904
|
+
"path": "The same signer repeatedly passes the voting Guard, re-triggering the vote-count side effect until the tally favors them.",
|
|
905
|
+
"viability": "viable",
|
|
906
|
+
"gate": "The anti-reentrancy primitive is absent or mis-wrapped, so no on-chain check blocks the repeat pass."
|
|
907
|
+
}
|
|
908
|
+
]
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "absent" }, { "field": "reentry_scene_id", "op": "eq", "value": "arbitration_usage_guard" }] },
|
|
913
|
+
"level": "high",
|
|
914
|
+
"title": "Reentrancy risk: ${reentry_scene_id} has NO anti-reentrancy protection (HIGH)",
|
|
915
|
+
"description": "Scene: ${reentry_scene_id}\nReentrancy risk level: HIGH\n\nRATIONALE:\n${reentry_rationale}\n\nDETECTION:\n${reentry_evidence}\n\nIMPACT: Without protection, the system can be abused (multiple dispute cases, arbitration harassment). Strongly recommended to add protection.\n\n",
|
|
916
|
+
"scenario": "${reentry_scene_id} lacks anti-reentrancy primitive; same Signer can repeatedly trigger the side effect",
|
|
917
|
+
"mitigation": "${reentry_mitigation}",
|
|
918
|
+
"evidence": "${reentry_evidence}",
|
|
919
|
+
"stakeholders": ["customer", "provider"]
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "absent" }, { "field": "reentry_scene_id", "op": "eq", "value": "service_order_allocators_guard" }] },
|
|
923
|
+
"level": "low",
|
|
924
|
+
"title": "Reentrancy reminder: ${reentry_scene_id} has no anti-reentrancy primitive (LOW risk)",
|
|
925
|
+
"description": "Scene: ${reentry_scene_id}\nReentrancy risk level: LOW\n\nRATIONALE:\n${reentry_rationale}\n\nDETECTION:\n${reentry_evidence}\n\nIMPACT: Low by default; only relevant if business intent requires single-action enforcement. Review the rationale above.\n\n",
|
|
926
|
+
"scenario": "${reentry_scene_id} lacks anti-reentrancy primitive; may or may not be needed depending on business intent",
|
|
927
|
+
"mitigation": "${reentry_mitigation}",
|
|
928
|
+
"evidence": "${reentry_evidence}",
|
|
929
|
+
"stakeholders": ["customer", "provider"]
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "absent" }, { "field": "reentry_scene_id", "op": "eq", "value": "service_buy_guard" }] },
|
|
933
|
+
"level": "low",
|
|
934
|
+
"title": "Reentrancy reminder: ${reentry_scene_id} has no anti-reentrancy primitive (LOW risk)",
|
|
935
|
+
"description": "Scene: ${reentry_scene_id}\nReentrancy risk level: LOW\n\nRATIONALE:\n${reentry_rationale}\n\nDETECTION:\n${reentry_evidence}\n\nIMPACT: Low by default; only relevant if business intent requires single-action enforcement. Review the rationale above.\n\n",
|
|
936
|
+
"scenario": "${reentry_scene_id} lacks anti-reentrancy primitive; may or may not be needed depending on business intent",
|
|
937
|
+
"mitigation": "${reentry_mitigation}",
|
|
938
|
+
"evidence": "${reentry_evidence}",
|
|
939
|
+
"stakeholders": ["provider"]
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "absent" }, { "field": "reentry_scene_id", "op": "eq", "value": "repository_write_guard" }] },
|
|
943
|
+
"level": "low",
|
|
944
|
+
"title": "Reentrancy reminder: ${reentry_scene_id} has no anti-reentrancy primitive (LOW risk)",
|
|
945
|
+
"description": "Scene: ${reentry_scene_id}\nReentrancy risk level: LOW\n\nRATIONALE:\n${reentry_rationale}\n\nDETECTION:\n${reentry_evidence}\n\nIMPACT: Low by default; only relevant if business intent requires single-action enforcement. Review the rationale above.\n\n",
|
|
946
|
+
"scenario": "${reentry_scene_id} lacks anti-reentrancy primitive; may or may not be needed depending on business intent",
|
|
947
|
+
"mitigation": "${reentry_mitigation}",
|
|
948
|
+
"evidence": "${reentry_evidence}",
|
|
949
|
+
"stakeholders": ["provider"]
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
"when": { "all": [{ "field": "reentry_applicable", "op": "eq", "value": true }, { "field": "reentry_state", "op": "eq", "value": "absent" }, { "field": "reentry_scene_id", "op": "eq", "value": "gen_passport_guard" }] },
|
|
953
|
+
"level": "low",
|
|
954
|
+
"title": "Reentrancy reminder: ${reentry_scene_id} has no anti-reentrancy primitive (LOW risk)",
|
|
955
|
+
"description": "Scene: ${reentry_scene_id}\nReentrancy risk level: LOW\n\nRATIONALE:\n${reentry_rationale}\n\nDETECTION:\n${reentry_evidence}\n\nIMPACT: Low by default; only relevant if business intent requires single-action enforcement. Review the rationale above.\n\n",
|
|
956
|
+
"scenario": "${reentry_scene_id} lacks anti-reentrancy primitive; may or may not be needed depending on business intent",
|
|
957
|
+
"mitigation": "${reentry_mitigation}",
|
|
958
|
+
"evidence": "${reentry_evidence}",
|
|
959
|
+
"stakeholders": ["provider"]
|
|
960
|
+
}
|
|
961
|
+
]
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
"rule_id": "R-X1-15",
|
|
965
|
+
"dimension": "logic_gap",
|
|
966
|
+
"trigger": "Guard root contains a progress.current query (id=1253 or name='progress.current'); if bound to a forward of the SAME Progress object, the guard evaluates before state transition",
|
|
967
|
+
"cases": [
|
|
968
|
+
{
|
|
969
|
+
"when": { "field": "root_has_progress_current_query", "op": "eq", "value": true },
|
|
970
|
+
"level": "medium",
|
|
971
|
+
"title": "Guard queries progress.current — verify it is NOT the same Progress object the hosting operation mutates",
|
|
972
|
+
"description": "Cognitive Principle P1: Guard validation ALWAYS occurs BEFORE the operation. This Guard contains a progress.current query. If this Guard is bound to a forward of the SAME Progress object it queries, the Guard will see the PRE-transition value (source node, not target node) and may always fail. Querying a DIFFERENT Progress object (e.g. another Machine's progress) is a valid and reasonable design pattern — the principle does not apply in that case. Allocator-bound guards are also unaffected because allocation.alloc() runs AFTER the state transition completes.",
|
|
973
|
+
"scenario": "Forward guard checks progress.current == target_node of the same Progress — always fails because the guard runs before the state transition sets the new current node",
|
|
974
|
+
"mitigation": "1) If this Guard queries the SAME Progress object the forward operates on: remove the guard from the forward, bind it ONLY to the Allocator (which runs after transition); OR change the check to verify the SOURCE node instead of the target node. 2) If this Guard queries a DIFFERENT Progress object (cross-machine): no action needed — this is a legitimate pattern. 3) The full principle and code evidence are stated in the description above (Cognitive Principle P1).",
|
|
975
|
+
"evidence": "Root contains progress.current query (id=1253). Query IDs detected: [${root_query_ids_csv}].",
|
|
976
|
+
"stakeholders": ["provider"]
|
|
977
|
+
}
|
|
978
|
+
]
|
|
979
|
+
}
|
|
980
|
+
]
|
|
981
|
+
}
|