Skip to content

security: fix auth, input validation, MQTT hardening, and modernize stack - #2

Merged
JoeRu merged 1 commit into
mainfrom
copilot/check-for-updates-and-security-issues
Jul 6, 2026
Merged

security: fix auth, input validation, MQTT hardening, and modernize stack#2
JoeRu merged 1 commit into
mainfrom
copilot/check-for-updates-and-security-issues

Conversation

Copilot AI commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Multiple security gaps and bugs in the webhook-to-MQTT bridge: unauthenticated endpoint, anonymous plaintext MQTT, no request body limit, silent crash on missing MQTT_SERVER, and a Python os.exit() that doesn't exist.

Bug fixes

  • os.exit()sys.exit(1) on missing MQTT_SERVER
  • respond() returns 400 when body is not valid JSON (previously passed None to worker thread, causing silent TypeError)

Security

  • Webhook auth: optional WEBHOOK_TOKEN env var; when set, requires Authorization: ****** on every POST /, returns 401` otherwise — with a startup warning if unset
  • Request size cap: MAX_CONTENT_LENGTH = 1 MB to prevent oversized payloads reaching MQTT
  • MQTT credentials: MQTT_USER / MQTT_PASSWORD env vars → client.username_pw_set()
  • MQTT TLS: MQTT_TLS=true env var → client.tls_set()
  • Hardcoded personal hostnames removed from docker-compose.yml; replaced with ${MQTT_SERVER} / ${WEBHOOK_HOST} variables. .env.example added; .env in .gitignore

Reliability

  • workit() thread wrapped in try/except — MQTT failures now logged instead of silently dropped
  • paho-mqtt migrated from CallbackAPIVersion.VERSION1VERSION2

Dependencies & image

  • Base image replaced: tiangolo/meinheld-gunicorn-flask:latest (unmaintained) → python:3.12-slim with explicit gunicorn CMD
  • requirements.txt added with pinned versions: Flask==3.1.3, paho-mqtt==2.1.0, gunicorn==26.0.0
  • Dockerfile simplified to a single pip install -r requirements.txt
  • Removed deprecated version: "3.6" key from docker-compose.yml

@JoeRu
JoeRu marked this pull request as ready for review July 6, 2026 19:48
Copilot AI review requested due to automatic review settings July 6, 2026 19:48
@JoeRu
JoeRu merged commit 57e2011 into main Jul 6, 2026
2 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the webhook-to-MQTT bridge by adding optional webhook authentication, request-size limiting, and MQTT TLS/credentials support, while also modernizing the container/base-image and pinning Python dependencies for more reproducible builds.

Changes:

  • Add optional WEBHOOK_TOKEN auth, 1MB request body cap, safer JSON handling, and improved MQTT publish robustness (TLS + user/pass + exception handling).
  • Modernize deployment: switch to python:3.12-slim, run via explicit gunicorn CMD, and add pinned requirements.txt.
  • Remove hardcoded personal hostnames from compose; add .env.example and ignore .env.

Reviewed changes

Copilot reviewed 4 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
requirements.txt Adds pinned Flask / paho-mqtt / gunicorn dependencies for reproducible installs.
Dockerfile Switches to python:3.12-slim, installs via requirements, runs Gunicorn explicitly.
docker-compose.yml Replaces hardcoded hostnames/envs with variable-driven configuration suitable for .env.
app/main.py Implements webhook auth, request size limit, MQTT auth/TLS, error handling, and fixes exit/JSON handling.
.gitignore Ignores .env to prevent committing secrets.
.env.example Documents the expected environment variables and recommended auth usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/main.py
Comment on lines +87 to +90
myparams = request.get_json()
if myparams is None:
logger.warning("Received non-JSON or empty request body")
return Response(status=400)
Comment thread app/main.py
Comment on lines +82 to +86
if webhook_token:
auth_header = request.headers.get('Authorization', '')
if auth_header != 'Bearer {}'.format(webhook_token):
logger.warning("Unauthorized request from {}".format(request.remote_addr))
return Response(status=401)
Comment thread app/main.py
Comment on lines +75 to +76
except Exception as e:
logger.error("Failed to publish MQTT message: {}".format(e))
Comment thread Dockerfile

COPY ./app /app

CMD ["gunicorn", "--bind", "0.0.0.0:80", "main:app"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants