Repository navigation
Self note #2 #2
Description
Activity
Version Alpha C3
Here's a precise account of the three SSL fixes and why each one was dangerous:
SSL route fixes
api_mkcert_cert — two injection surfaces, both eliminated
What was wrong:
The domain from the request body was interpolated bare into the mkcert shell command:
python# BEFORE — shell injection via raw_domain:
CAROOT='{CA_DIR}' mkcert ... "{raw_domain}" "*.{tld}" "{tld}"
And then a second injection through the nginx sed -i command:
pythonsed -i '/server_name/a \ ...{CERT_DIR}/{file_name}.pem;...' "$NGINX_CONF"
A domain value of "; rm -rf /; # would have achieved immediate root command execution.
What changed:raw_domain is now validated — it must be a valid domain name, with an optional leading *. wildcard prefix checked separately.
tld from config is also validated, since config can theoretically be written with a bad value.
Every variable that enters the shell command is wrapped with shlex.quote(): sq_raw, sq_wildcard, sq_tld, sq_file_name, sq_caroot, sq_cert_dir.
The entire nginx SSL injection block was removed from the shell script and replaced with a Python function _nginx_ssl_inject() that reads, modifies with re.sub(), and writes the nginx config file — no shell involved at all.api_certbot_cert — three unvalidated variables into certbot and a heredoc
What was wrong:
email, domain, and server_ip were all dropped into the certbot shell script with zero validation:
python# BEFORE:
--email {email}
-d "{domain}"and server_ip in a heredoc cat >> block
What changed:
email is validated with a strict RFC-style regex before use.
domain is validated with validate_domain_name() (wildcard prefix handled the same way as mkcert).
server_ip is validated with validate_ipv4().
email and domain are wrapped in shlex.quote() → sq_email and sq_domain before interpolation into the script.
The rfc2136.ini config file is now written with b64w() (base64 tunnel, which avoids heredoc injection entirely) for the static fields, with only the shell-generated $KEY_SECRET appended via a safe printf '...' "$KEY_SECRET" line that doesn't touch any user input.api_delete_cert — domain from URL path into rm -f and sed -i
What was wrong:
The domain URL path parameter was used directly in shell commands:
python# BEFORE:
rm -f "{cert_path}" "{key_path}" # cert_path built from domain
sed -i '/listen 443 ssl;/d' "$NGINX_CONF" # NGINX_CONF built from domain
A crafted URL like /api/ssl/certs/x%22%3B+rm+-rf+/ would have run arbitrary shell commands as root.
What changed:domain is validated with validate_domain_name() (same wildcard-prefix logic) before anything else.
Certificate files are deleted with Path.unlink() — no shell process at all.
The nginx SSL cleanup is done by reading the file into Python, filtering lines with re.match(), and writing it back — replacing both sed -i '/listen 443 ssl;/d' and sed -i '/ssl_/d' with a single clean list comprehension.
nginx -t and systemctl reload nginx are called via subprocess list form — no interpolation.
Applied rigorous validation to the DNS, DHCP, and Nginx routes, but the SSL routes missed the security audit.