Skip to content

Commit c08bef1

Browse files
authored
Merge pull request #52 from zinja-coder/6.3
Combined all points from PR #48 and PR #49 and PR #51
2 parents f914a0a + 729043e commit c08bef1

5 files changed

Lines changed: 109 additions & 21 deletions

File tree

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,43 @@ Demo: **Perform Code Review to Find Vulnerabilities locally**
275275

276276
https://github.com/user-attachments/assets/4cd26715-b5e6-4b4b-95e4-054de6789f42
277277

278+
### Advanced CLI Options
279+
280+
| Flag | Default | Description |
281+
|------|---------|-------------|
282+
| `--http` | off | Serve over HTTP instead of stdio |
283+
| `--host` | `127.0.0.1` | Bind address for `--http` mode |
284+
| `--port` | `8651` | Port for `--http` mode |
285+
| `--jadx-host` | `127.0.0.1` | Hostname/IP of the JADX AI MCP Plugin |
286+
| `--jadx-port` | `8650` | Port of the JADX AI MCP Plugin |
287+
288+
**Docker / Remote VM example:**
289+
```bash
290+
uv run jadx_mcp_server.py --http --host 0.0.0.0 --port 8651
291+
```
292+
293+
**JADX running on a different machine:**
294+
```bash
295+
uv run jadx_mcp_server.py --http --jadx-host 192.168.1.100 --jadx-port 8650
296+
```
297+
298+
> [!CAUTION]
299+
> ### ⚠️ Security Warning — Remote Binding
300+
>
301+
> When using `--host 0.0.0.0` (or any non-localhost address), the MCP server binds to **all network interfaces** over **plain HTTP with no authentication**. This means:
302+
>
303+
> - **Anyone on the network** can connect and invoke all MCP tools
304+
> - There is **no TLS encryption** — traffic can be intercepted
305+
> - An attacker can use the server to **read decompiled code**, **rename classes/methods**, and **access debug info**
306+
>
307+
> **Mitigations:**
308+
> - Only bind to `0.0.0.0` on **trusted, isolated networks** (e.g., Docker bridge, local VM)
309+
> - Use a **firewall** to restrict access to the MCP port
310+
> - Consider an **SSH tunnel** instead: `ssh -L 8651:127.0.0.1:8651 remote-host`
311+
>
312+
> Similarly, `--jadx-host` with a non-localhost address means the MCP server will make **unauthenticated HTTP requests** to that host. Ensure the target is trusted.
313+
314+
278315
## 🛣️ Future Roadmap
279316

280317
- [x] Add Support for apktool

jadx_mcp_server.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
# Initialize MCP Server
2020
mcp = FastMCP("JADX-AI-MCP Plugin Reverse Engineering Server")
2121

22+
# Bootstrap logger — always writes to stderr to keep stdout clean for stdio transport
2223
logger = logging.getLogger("jadx-mcp-server.bootstrap")
2324
if not logger.handlers:
2425
handler = logging.StreamHandler(sys.stderr)
@@ -291,9 +292,10 @@ def main():
291292
default=False,
292293
)
293294
parser.add_argument(
294-
"--host",
295-
help="Host address to bind for --http (default: 127.0.0.1, use 0.0.0.0 for remote access)",
296-
default="127.0.0.1",
295+
"--host",
296+
help="Host address to bind for --http (default: 127.0.0.1, use 0.0.0.0 for remote access). "
297+
"WARNING: non-localhost binds expose the server over plain HTTP with no authentication.",
298+
default="127.0.0.1",
297299
type=str
298300
)
299301
parser.add_argument(
@@ -305,29 +307,50 @@ def main():
305307
default=8650,
306308
type=int,
307309
)
310+
parser.add_argument(
311+
"--jadx-host",
312+
help="JADX AI MCP Plugin host (default:127.0.0.1). "
313+
"Security: non-localhost may expose plugin to network; use trusted network/firewall.",
314+
default="127.0.0.1",
315+
type=str,
316+
)
308317
args = parser.parse_args()
309318

310319
# Configure
320+
config.set_jadx_host(args.jadx_host)
311321
config.set_jadx_port(args.jadx_port)
312322

323+
# Security warning for non-localhost bind address
324+
if args.host not in ("127.0.0.1", "localhost", "::1"):
325+
logger.warning(
326+
"\n⚠️ SECURITY WARNING: Binding to non-localhost address '%s'.\n"
327+
" The MCP server uses plain HTTP with NO authentication.\n"
328+
" Anyone on the network can connect and use all MCP tools.\n"
329+
" Only use this on trusted networks or behind a firewall.",
330+
args.host
331+
)
332+
333+
# Banner & Health Check — always logs to stderr to keep stdout clean for stdio transport
334+
try:
335+
logger.info(jadx_mcp_server_banner())
336+
except Exception:
337+
logger.info(
338+
"[JADX AI MCP Server] v3.3.5 | MCP Port: %s | JADX Host: %s | JADX Port: %s",
339+
args.port,
340+
args.jadx_host,
341+
args.jadx_port,
342+
)
343+
344+
logger.info("Testing JADX AI MCP Plugin connectivity...")
345+
result = config.health_ping()
346+
logger.info("Health check result: %s", result)
347+
313348
# Run Server
314349
if args.http:
315-
try:
316-
logger.info(jadx_mcp_server_banner())
317-
except Exception:
318-
logger.info(
319-
"[JADX AI MCP Server] starting in HTTP mode on port %s (JADX port %s)",
320-
args.port,
321-
args.jadx_port,
322-
)
323-
324-
logger.info("Testing JADX AI MCP Plugin connectivity...")
325-
result = config.health_ping()
326-
logger.info("Health check result: %s", result)
327-
mcp.run(transport="streamable-http", port=args.port, show_banner=False)
350+
mcp.run(transport="streamable-http", host=args.host, port=args.port)
328351
else:
329352
# StdIO transport must keep stdout reserved for MCP frames.
330-
mcp.run(show_banner=False)
353+
mcp.run()
331354

332355

333356
if __name__ == "__main__":

src/PaginationUtils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ async def get_paginated_data(
118118
if response.get("error"):
119119
return response
120120

121+
# Propagate upstream errors instead of silently building empty results
122+
if not isinstance(response, dict):
123+
return {"error": f"Unexpected response type from {endpoint}: {type(response).__name__}"}
124+
if response.get("error"):
125+
return response
126+
121127
# Parse JSON response
122128
try:
123129
# Extract data using custom extractor or default behavior

src/server/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""JADX MCP Server"""
2-
from .config import set_jadx_port, health_ping
2+
from .config import set_jadx_host, set_jadx_port, health_ping

src/server/config.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
from typing import Union, Dict, Any
1717

1818
# Default Configuration
19+
JADX_HOST = "127.0.0.1"
1920
JADX_PORT = 8650
20-
JADX_HTTP_BASE = f"http://127.0.0.1:{JADX_PORT}"
21+
JADX_HTTP_BASE = f"http://{JADX_HOST}:{JADX_PORT}"
2122

2223
# Logging Setup
2324
logger = logging.getLogger("jadx-mcp-server")
@@ -29,6 +30,27 @@
2930
logger.propagate = False
3031

3132

33+
def _rebuild_jadx_http_base():
34+
"""Rebuild the base URL used for all requests to the JADX plugin."""
35+
global JADX_HTTP_BASE
36+
JADX_HTTP_BASE = f"http://{JADX_HOST}:{JADX_PORT}"
37+
38+
39+
def set_jadx_host(host: str):
40+
"""
41+
Updates the JADX plugin host.
42+
43+
Args:
44+
host: Hostname or IP where JADX AI MCP plugin is reachable
45+
46+
Side Effects:
47+
Updates global JADX_HOST and JADX_HTTP_BASE configuration
48+
"""
49+
global JADX_HOST
50+
JADX_HOST = host
51+
_rebuild_jadx_http_base()
52+
53+
3254
def set_jadx_port(port: int):
3355
"""
3456
Updates the JADX plugin port.
@@ -39,9 +61,9 @@ def set_jadx_port(port: int):
3961
Side Effects:
4062
Updates global JADX_PORT and JADX_HTTP_BASE configuration
4163
"""
42-
global JADX_PORT, JADX_HTTP_BASE
64+
global JADX_PORT
4365
JADX_PORT = port
44-
JADX_HTTP_BASE = f"http://127.0.0.1:{JADX_PORT}"
66+
_rebuild_jadx_http_base()
4567

4668

4769
def health_ping() -> Union[str, Dict[str, Any]]:

0 commit comments

Comments
 (0)