Files
heretek-control-core/bin/package.json
T
Mian Shahzad Raza f5ad66ed42 fix(security): act on the repository security scan
Seven findings, all verified against the code first. None is reachable
by an anonymous visitor: each needs an administrator, or a URL an
administrator already asked the plugin to fetch.

F-01, the one that mattered. safe_download() checked the URL you gave it
with the strong guard, then handed redirects to WP_Http with
reject_unsafe_urls, which only applies core's weaker check. The file's
own comment already said core does not reject 169.254.0.0/16, so a URL
could pass and then bounce to the cloud metadata service, with the
response written into the Media Library. Redirects are now followed by
hand with the full check on every hop. The address check itself also
read only the first A record, so a host publishing one public and one
internal address passed: host_is_blocked() now requires every answer,
A and AAAA, to be public, and fails closed when a host resolves to
nothing. Rebinding is still out of scope here and the docblock says so.

F-02. search-files judged and read each hit by the path it walked, which
for a symlink is the link. Its basename defeated the secret check and
reading it followed the link out of ABSPATH, so a link named notes.txt
pointing at wp-config.php answered a search for DB_PASSWORD. Every hit
now goes through resolve_path() first, which is what read-file already
did. Listings label symlinks instead of presenting them as files.

F-04. The read-protected list was one exact filename. Now covers .env,
wp-config.* copies, .htpasswd, auth.json, key files, and anything under
.git. .htaccess stays readable on purpose: it is not a secret.

F-03. The proxy disabled certificate verification for any host ending
in .dev, which is a real gTLD anyone can register, while sending an
Application Password on every request. Removed; EMCP_INSECURE_TLS=1 is
the opt-in. Package to 1.11.0 since it is published.

F-05. Two sandbox guards used wp_normalize_path(), which does not
resolve "..", so the containment check they exist to make did not hold.
Both resolve properly now. Defense in depth: the hash check beside them
is what actually held.

F-06. The update package URL is now asserted to be a release asset of
this repository before the upgrader is handed it.

F-07. The snippet validator skipped every method call, so a function on
its critical list reached as $file->fwrite() was never looked up.
Reported as a warning rather than critical, because a name alone does
not identify the object and falsely blocking someone's $wpdb->query()
is worse than a line a reviewer reads.

One correction to the report: validate_pinned() is not "called from
nowhere". The Pro AI Chat fetcher uses it per hop with CURLOPT_RESOLVE
pinning; the scan could not see pro/.

Live-verified on msrplugins.test: the six address cases behave, a real
119KB download still completes through the rewritten loop, redirect
targets to metadata and RFC1918 are refused, and a refused download
leaves no temp file behind. Suites: pro 2541, public 155, proxy 14.
2026-08-22 14:43:27 +05:00

42 lines
990 B
JSON

{
"name": "@msrbuilds/emcp-proxy",
"version": "1.11.0",
"description": "stdio↔HTTP proxy that connects MCP clients (Claude Desktop, Claude Code, etc.) to one or many remote WordPress sites running the MCP Tools for Elementor (EMCP) plugin.",
"type": "module",
"bin": {
"emcp-proxy": "mcp-proxy.mjs"
},
"main": "./mcp-proxy.mjs",
"files": [
"mcp-proxy.mjs",
"README.md"
],
"engines": {
"node": ">=18"
},
"license": "GPL-2.0-or-later",
"author": "MSR Builds",
"homepage": "https://emcptools.com/docs/connecting/claude-desktop/",
"repository": {
"type": "git",
"url": "git+https://github.com/msrbuilds/elementor-mcp.git",
"directory": "bin"
},
"bugs": {
"url": "https://github.com/msrbuilds/elementor-mcp/issues"
},
"keywords": [
"mcp",
"model-context-protocol",
"elementor",
"wordpress",
"claude",
"claude-desktop",
"proxy",
"stdio"
],
"publishConfig": {
"access": "public"
}
}