T09 · Insecure Skill Coding Practices
- Location
scripts/garage.sh:43- Finding
Garage Door Safety Check Fails Open on Invalid or Unavailable Status Data
- Content
View full analysis
Vulnerability Details
File Location:
scripts/garage.sh, lines 43–58
Vulnerability Type: Fail-open safety validation and insufficient HTTP error handling
Risk Level: Highbash safe_close() { local json json=$(curl -s --connect-timeout 5 "${BASE}/status.json") local obstructed obstructed=$(echo "$json" | python3 -c "import json,sys; print(json.load(sys.stdin).get('garageObstructed', False))") if [ "$obstructed" = "True" ]; then echo "BLOCKED: Obstruction detected — cannot close door" exit 1 fi local state state=$(echo "$json" | python3 -c "import json,sys; print(json.load(sys.stdin).get('garageDoorState', '?'))") if [ "$state" = "closed" ]; then echo "Already closed" exit 0 fi control "garageDoorState" "0" "Closing door" }The affected operation invokes the following helper at lines 32–41:
bash control() { local field="$1" value="$2" label="$3" curl -s -X POST -F "${field}=${value}" "${BASE}/setgdo" > /dev/null if [ $? -eq 0 ]; then echo "OK: ${label}" else echo "ERROR: Failed to ${label}" exit 1 fi }Technical Analysis
safe_closedoes not validate whether the status request succeeded, returned a successful HTTP status, contained nonempty data, or produced a valid and complete status object. The script also does not enable shell behavior that would terminate execution when either Python parsing command fails.If the response is valid JSON but omits
garageObstructed, the expression.get('garageObstructed', False)explicitly interprets the missing safety field as no obstruction. If the response is empty or malformed, Python exits unsuccessfully, but the failure is ignored andobstructedbecomes empty. Because an empty value is not equal toTrue, execution continues toward the physical close command.The current door-stat ...[truncated 2374 chars]
- Remediation
View remediation
Remediation Suggestions
- Make status validation fail closed. Abort unless the status request succeeds and explicitly reports
garageObstructedas the boolean valuefalse. - Use strict curl error handling, including
--fail,--show-error, a connection timeout, and an overall request timeout. - Parse the status response once and validate its schema. Require both
garageObstructedandgarageDoorStateto exist with expected types and values. - Check every parser exit status. Do not proceed when JSON is empty, malformed, incomplete, or semantically invalid.
- Treat unknown door states as fatal rather than issuing a close command.
- Validate the control response and, where supported, query status afterward to confirm that the requested state transition actually began.
- Prefer authenticated HTTPS if supported by the controller. Otherwise, isolate the device and calling host on a trusted VLAN and use a fixed IP or otherwise protected name resolution to reduce LAN spoofing risk.
- Consider strict shell options such as
set -euo pipefail, while still implementing explicit error handling for safety-critical requests.
A hardened implementation should follow this pattern:
bash safe_close() { local json parsed obstructed state if ! json=$(curl --fail --silent --show-error \ --connect-timeout 5 --max-time 10 \ "${BASE}/status.json"); then echo "ERROR: Unable to obtain garage safety status" >&2 exit 1 fi if ! parsed=$(printf '%s' "$json" | python3 -c ' import json import sys data = json.load(sys.stdin) if type(data.get("garageObstructed")) is not bool: raise ValueError("Missing or invalid garageObstructed") if data.get("garageDoorState") not in { "open", "closed", "opening", "closing", "stopped" }: raise ValueError("Missing or invalid garageDoorState") print("true" if data["garageObstructed"] else "false") print(data["garageDoorSta ...[truncated 767 chars]- Make status validation fail closed. Abort unless the status request succeeds and explicitly reports
