@grampro/kit 2.7.0 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +7 -1
- package/package.json +2 -2
- package/source/components/accordion/passport.json +1 -1
- package/source/components/alert/passport.json +1 -1
- package/source/components/avatar/passport.json +1 -1
- package/source/components/badge/passport.json +1 -1
- package/source/components/breadcrumb/passport.json +1 -1
- package/source/components/button/passport.json +1 -1
- package/source/components/card/passport.json +1 -1
- package/source/components/checkbox/passport.json +1 -1
- package/source/components/combobox/passport.json +1 -1
- package/source/components/data-grid/passport.json +1 -1
- package/source/components/date-picker/passport.json +1 -1
- package/source/components/dialog/passport.json +1 -1
- package/source/components/file-uploader/passport.json +1 -1
- package/source/components/input/passport.json +1 -1
- package/source/components/menu/passport.json +1 -1
- package/source/components/modal/passport.json +1 -1
- package/source/components/number-input/passport.json +1 -1
- package/source/components/popover/passport.json +1 -1
- package/source/components/progress/passport.json +1 -1
- package/source/components/radio-group/passport.json +1 -1
- package/source/components/skeleton/passport.json +1 -1
- package/source/components/spinner/passport.json +1 -1
- package/source/components/switch/passport.json +1 -1
- package/source/components/tabs/passport.json +1 -1
- package/source/components/textarea/passport.json +1 -1
- package/source/components/toaster/passport.json +1 -1
- package/source/components/tooltip/passport.json +1 -1
- package/tools/mcp/README.md +23 -0
- package/tools/mcp/server.cjs +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.7.1
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
**get_guidance could read any .md file on disk.** It appended `.md` to a
|
|
8
|
+
caller-supplied `topic` and joined it onto the references folder with no
|
|
9
|
+
traversal guard, so `topic = "../../../../CHANGELOG"` returned the repo
|
|
10
|
+
CHANGELOG and the same trick reached any `.md` file the server process could
|
|
11
|
+
open. Found by a VAPT pass driving the tool with traversal payloads. The
|
|
12
|
+
server runs with your own authority, so it is a confused-deputy hole rather
|
|
13
|
+
than privilege escalation — but a tool that advertises nine fixed topics
|
|
14
|
+
should not become a file-exfiltration primitive for a prompt-injected agent.
|
|
15
|
+
It now refuses any `topic` that is not one of the shipped guidance names, with
|
|
16
|
+
a resolved-prefix check behind the allowlist. A regression test drives the
|
|
17
|
+
same payloads.
|
|
18
|
+
|
|
19
|
+
**Affected: 2.4.4 through 2.7.0** — every release that has shipped the MCP
|
|
20
|
+
server. Each was checked by running the same payload against its published
|
|
21
|
+
tarball. 2.4.3 and earlier have no MCP server and are not affected. A project
|
|
22
|
+
that installed the package locally needs `npm i -D @grampro/kit@latest`. One
|
|
23
|
+
configured with `npx -y @grampro/kit mcp` may keep running a cached copy; check
|
|
24
|
+
with `npx -y @grampro/kit --version`, and if it is not 2.7.1, run
|
|
25
|
+
`npx -y @grampro/kit@2.7.1 mcp` once to replace it.
|
|
26
|
+
|
|
3
27
|
## 2.7.0
|
|
4
28
|
|
|
5
29
|
### Added
|
package/README.md
CHANGED
|
@@ -135,7 +135,13 @@ anything first.
|
|
|
135
135
|
No dependencies, and it starts in about the time an empty Node process
|
|
136
136
|
takes. Full walkthrough, including a prompt to paste:
|
|
137
137
|
[kit.gramproindia.com/mcp-server](https://kit.gramproindia.com/mcp-server).
|
|
138
|
-
Details in [`tools/mcp/README.md`](tools/mcp/README.md)
|
|
138
|
+
Details in [`tools/mcp/README.md`](tools/mcp/README.md), including what a tool
|
|
139
|
+
call can and cannot reach.
|
|
140
|
+
|
|
141
|
+
**Use 2.7.1 or later.** From 2.4.4 through 2.7.0, a crafted `get_guidance`
|
|
142
|
+
call could read any `.md` file the server could open. The
|
|
143
|
+
[changelog](CHANGELOG.md#271) explains how to check which version your agent
|
|
144
|
+
is running.
|
|
139
145
|
|
|
140
146
|
## Figma plugin
|
|
141
147
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grampro/kit",
|
|
3
|
-
"version": "2.7.
|
|
4
|
-
"description": "GramproKit
|
|
3
|
+
"version": "2.7.1",
|
|
4
|
+
"description": "GramproKit — an agent-native UI runtime for React. Copy-in components you own, each publishing a contract that software can read.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.cjs",
|
package/tools/mcp/README.md
CHANGED
|
@@ -266,3 +266,26 @@ CLI's own dependencies, which are no use to a JSON-RPC loop and cost around
|
|
|
266
266
|
The catalogue it serves is the one in this package, not the components
|
|
267
267
|
copied into your project — so an agent can see a component before you
|
|
268
268
|
install it, and `install_component` puts it in place.
|
|
269
|
+
|
|
270
|
+
### What a caller can reach
|
|
271
|
+
|
|
272
|
+
Every tool argument is treated as untrusted. An agent that has read a hostile
|
|
273
|
+
web page or design file can be steered into calling these tools with
|
|
274
|
+
anything, so the boundary has to hold no matter who wrote the arguments.
|
|
275
|
+
|
|
276
|
+
- **`get_guidance`** serves only the guidance topics that ship in this
|
|
277
|
+
package. Any other topic is refused, including one containing `../`. Before
|
|
278
|
+
2.7.1 it was not refused: a crafted topic could read any `.md` file the
|
|
279
|
+
server could open. See the changelog.
|
|
280
|
+
- **`get_component`, `get_example` and `install_component`** accept only names
|
|
281
|
+
in the catalogue. A name is reduced to letters and digits before anything
|
|
282
|
+
is looked up, and `install_component` runs the CLI with an argument list,
|
|
283
|
+
never through a shell.
|
|
284
|
+
- **`figma_frame` with `designFile`** reads the path it is given, with your
|
|
285
|
+
user's permissions. It only returns content from a file shaped like the
|
|
286
|
+
plugin's export, and refuses anything else without quoting it. A file that
|
|
287
|
+
*is* shaped like an export gets read as one, which is the tool's purpose.
|
|
288
|
+
|
|
289
|
+
The server runs as you, so none of this stops an agent that can already read
|
|
290
|
+
your files directly. What it prevents is a tool that advertises one narrow
|
|
291
|
+
job being turned into a general file reader.
|
package/tools/mcp/server.cjs
CHANGED
|
@@ -197,7 +197,23 @@ function getGuidance(topic) {
|
|
|
197
197
|
? fs.readdirSync(REFERENCES).filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, ""))
|
|
198
198
|
: [];
|
|
199
199
|
if (!topic) return { topics: available };
|
|
200
|
+
|
|
201
|
+
/*
|
|
202
|
+
* `topic` is caller-controlled, and `path.join(REFERENCES, topic + ".md")`
|
|
203
|
+
* followed a `../` out of the references folder: a prompt-injected agent
|
|
204
|
+
* could turn this into "read any .md file on disk". The list is already an
|
|
205
|
+
* allowlist of what actually ships, so a topic that is not one of those
|
|
206
|
+
* names is refused before any path is built. The resolved-prefix check is
|
|
207
|
+
* the belt to that braces — it also stops a name that readdir would never
|
|
208
|
+
* produce, such as one reaching through a symlink.
|
|
209
|
+
*/
|
|
210
|
+
if (!available.includes(topic)) {
|
|
211
|
+
return { error: `No guidance for "${topic}".`, topics: available };
|
|
212
|
+
}
|
|
200
213
|
const file = path.join(REFERENCES, `${topic}.md`);
|
|
214
|
+
if (!path.resolve(file).startsWith(path.resolve(REFERENCES) + path.sep)) {
|
|
215
|
+
return { error: `No guidance for "${topic}".`, topics: available };
|
|
216
|
+
}
|
|
201
217
|
if (!fs.existsSync(file)) return { error: `No guidance for "${topic}".`, topics: available };
|
|
202
218
|
return { topic, text: fs.readFileSync(file, "utf8") };
|
|
203
219
|
}
|