Unconnected Component Inputs
Detects component instantiations where outputs are read but inputs are not wired, leaving the sub-circuit unconstrained and enabling proof forgery.
Unconnected Component Inputs
Overview
Remediation Guide: How to Fix Unconnected Component Inputs
The unconnected component inputs detector identifies cases where a component is instantiated and its outputs are read, but none of its inputs are wired. When a component’s inputs are not connected, the sub-circuit’s computation is unconstrained — the prover controls what values the outputs take, and the verifier cannot detect the manipulation.
Circom components are template instances. When you write component h = Poseidon(1), the Poseidon template’s constraints are included in the R1CS, but the template’s input signals are free variables unless you wire them. If you read h.out without ever assigning h.inputs[0], the prover can set h.out to any value that satisfies Poseidon’s constraints for some arbitrary input.
Why This Is an Issue
Components encapsulate sub-circuits. Their inputs must be wired to parent signals (via <==) so that the sub-circuit’s constraints connect to the parent circuit. Without input wiring, the component is an isolated island of constraints — the prover can satisfy them independently with any values, then feed those values back into the parent circuit.
A common scenario: a developer instantiates a hash component, reads the output, but forgets to wire the input. The prover can then set the “hash output” to any value, bypassing the hash computation entirely.
How to Resolve
Wire all component inputs using constraining assignments (<==).
// Before: Vulnerable -- component output used, but input never wired
component hasher = Poseidon(1);
// hasher.inputs[0] is never assigned!
digest <== hasher.out; // prover controls this value
// After: Fixed -- input wired via <==
component hasher = Poseidon(1);
hasher.inputs[0] <== preimage; // input is now constrained
digest <== hasher.out; // output is determined by preimage
Examples
Vulnerable Code
template BrokenVerifier() {
signal input data;
signal output hash;
component h = Poseidon(1);
// BUG: h.inputs[0] is never assigned
hash <== h.out; // output is read but input is floating
}
The prover can satisfy Poseidon’s internal constraints with any input and produce a corresponding output. Since no parent signal is wired to h.inputs[0], the hash bears no relation to data.
Fixed Code
template CorrectVerifier() {
signal input data;
signal output hash;
component h = Poseidon(1);
h.inputs[0] <== data; // input wired to parent signal
hash <== h.out; // output is now determined by `data`
}
Sample Sigvex Output
CRITICAL unconnected-component-inputs
Component outputs used but inputs not connected
Component 'h' (type 'Poseidon') has outputs read but no inputs are assigned.
The component's computation is unconstrained -- the prover can set the outputs
to arbitrary values.
Template: BrokenVerifier
Confidence: 0.85
Recommendation: Wire all component inputs using `<==` to ensure the sub-circuit
is properly constrained.
Detection Methodology
For each component instantiation within a template, the detector builds two sets:
- Connected inputs: signals written to the component via assignments where the LHS matches
component_name.signal_name(e.g.,h.inputs[0] <== data). - Connected outputs: signals read from the component, detected by scanning assignment RHS expressions for references matching
component_name.signal_name(e.g.,hash <== h.out).
Three cases are checked:
- No connections at all: the component is instantiated but never used (reported as a separate “disconnected-component” finding at High severity).
- Outputs read but no inputs wired: the critical case this detector targets (reported at Critical severity, confidence 0.85).
- Inputs wired but outputs unused: not flagged by this detector (the component’s constraints are active, just unused results).
Limitations
- Pattern-based input detection. If inputs are wired through an intermediate computation or via dynamic assignment patterns, the detector may not recognize the connection.
- Does not verify that all inputs are wired — only that at least one is. A component with 3 inputs where only 1 is wired will not be flagged. Partial wiring detection is planned.
- Array-indexed component inputs (e.g.,
h.inputs[i]whereiis a variable) may not be recognized.
Related Detectors
- under-constrained-signal — general under-constrained signal detection
- unconstrained-output — output signals without constraints
- unconstrained-public-input — public inputs not bound by constraints
References
- Circom Documentation: Components
- circomlib GitHub repository — reference implementations of common components
- Circom Documentation: Constraint Generation