API endpoint leaks config #7

Closed
opened 2026-10-05 06:01:40 +02:00 by adam · 6 comments
Owner

I don't know the usecase for this endpoint, but it seems like it shouldn’t expose the entire config freely. For the most part it’s not particularly sensitive. However, some users may wish to keep the MQTT credentials or topic info private to prevent them from being used for undesired downlinking. Database connection strings can also be sensitive, though less true for sqlite I suppose. Also if the config ever grows to include more sensitive info it will automatically be leaked here as it is now.

It should either redact or omit credentials, or perhaps this endpoint is only available if DEBUG=True.

https://github.com/pablorevilla-meshtastic/meshview/blob/d5272c1aecf366709d7be90ab388f85d0e16cc72/meshview/web.py#L1583-L1589

I don't know the usecase for this endpoint, but it seems like it shouldn’t expose the entire config freely. For the most part it’s not particularly sensitive. However, some users may wish to keep the MQTT credentials or topic info private to prevent them from being used for undesired downlinking. Database connection strings can also be sensitive, though less true for sqlite I suppose. Also if the config ever grows to include more sensitive info it will automatically be leaked here as it is now. It should either redact or omit credentials, or perhaps this endpoint is only available if `DEBUG=True`. https://github.com/pablorevilla-meshtastic/meshview/blob/d5272c1aecf366709d7be90ab388f85d0e16cc72/meshview/web.py#L1583-L1589 <!-- github-sync-id:3428297535 -->
adam closed this issue 2026-10-05 06:01:40 +02:00
Author
Owner

Agreed. I had to block it in my nginx config.

Agreed. I had to block it in my nginx config. <!-- github-comment-id:3305443284 -->
Author
Owner

Thank you for bringing it up. yes good point.

Thank you for bringing it up. yes good point. <!-- github-comment-id:3305479949 -->
Author
Owner

Well the idea was to make the API available so that you could technically do most of the website with javascript and APi. The hope is that more code could be done in JS. (that was my thought...) now would it be ok if it only shows the site details a limited set of values?


@routes.get("/api/config")
async def api_config(request):
    try:
        # Make a sanitized copy (only keep safe fields)
        safe_config = {
            "site": CONFIG.get("site", {}),
        }

        return web.json_response(safe_config)
    except Exception as e:
        return web.json_response({"error": str(e)}, status=500)

This will allow to get some "safe" information to JS when needed.

{
"site": {
"domain": "",
"title": "Bay Area Mesh",
"message": "Real time data from around the bay area and beyond.",
"starting": "/chat",
"nodes": "True",
"conversations": "True",
"everything": "True",
"graphs": "True",
"stats": "True",
"net": "True",
"map": "True",
"top": "True",
"map_top_left_lat": "39",
"map_top_left_lon": "-123",
"map_bottom_right_lat": "36.5",
"map_bottom_right_lon": "-119.5",
"map_interval": "3",
"firehose_interal": "3",
"weekly_net_message": "Weekly Mesh check-in. We will keep it open on every Wednesday from 5:00pm for checkins. The message format should be (LONG NAME) - (CITY YOU ARE IN) #BayMeshNet.",
"net_tag": "#BayMeshNet"
}
}

Well the idea was to make the API available so that you could technically do most of the website with javascript and APi. The hope is that more code could be done in JS. (that was my thought...) now would it be ok if it only shows the site details a limited set of values? ``` @routes.get("/api/config") async def api_config(request): try: # Make a sanitized copy (only keep safe fields) safe_config = { "site": CONFIG.get("site", {}), } return web.json_response(safe_config) except Exception as e: return web.json_response({"error": str(e)}, status=500) ``` This will allow to get some "safe" information to JS when needed. { "site": { "domain": "", "title": "Bay Area Mesh", "message": "Real time data from around the bay area and beyond.", "starting": "/chat", "nodes": "True", "conversations": "True", "everything": "True", "graphs": "True", "stats": "True", "net": "True", "map": "True", "top": "True", "map_top_left_lat": "39", "map_top_left_lon": "-123", "map_bottom_right_lat": "36.5", "map_bottom_right_lon": "-119.5", "map_interval": "3", "firehose_interal": "3", "weekly_net_message": "Weekly Mesh check-in. We will keep it open on every Wednesday from 5:00pm for checkins. The message format should be (LONG NAME) - (CITY YOU ARE IN) #BayMeshNet.", "net_tag": "#BayMeshNet" } } <!-- github-comment-id:3305512748 -->
Author
Owner

even more restrictive

{
  "site": {
    "map_interval": "3",
    "firehose_interval": "4"
  }
}
even more restrictive ``` { "site": { "map_interval": "3", "firehose_interval": "4" } } ``` <!-- github-comment-id:3305530691 -->
Author
Owner

just updated the code to have the more restrictive output

just updated the code to have the more restrictive output <!-- github-comment-id:3305554815 -->
Author
Owner
@routes.get("/api/config")
async def api_config(request):
    try:
        site = CONFIG.get("site", {})
        safe_site = {
            "map_interval": site.get("map_interval", 3),        # default 3 if missing
            "firehose_interval": site.get("firehose_interval", 3)  # default 3 if missing
        }

        safe_config = {"site": safe_site}

        return web.json_response(safe_config)
    except Exception as e:
        return web.json_response({"error": str(e)}, status=500)
``` @routes.get("/api/config") async def api_config(request): try: site = CONFIG.get("site", {}) safe_site = { "map_interval": site.get("map_interval", 3), # default 3 if missing "firehose_interval": site.get("firehose_interval", 3) # default 3 if missing } safe_config = {"site": safe_site} return web.json_response(safe_config) except Exception as e: return web.json_response({"error": str(e)}, status=500) ``` <!-- github-comment-id:3305560253 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/meshview#7