Sign In

@mindstone/mcp-server-quickbooks

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mindstone/mcp-server-quickbooks - npm Package Compare versions

Comparing version
0.4.1
to
0.4.2
+3
-3
dist/untrusted-content.d.ts

@@ -23,4 +23,4 @@ /**

* Wrap a single untrusted string in an `<untrusted-content source="…">`
* envelope, escaping any embedded close-tag variant so the envelope cannot be
* broken out of.
* envelope, escaping any embedded open/close-tag variant so the envelope can
* neither be broken out of nor have a spoofed nested envelope planted inside.
*

@@ -32,3 +32,3 @@ * `undefined` and `null` are passed through untouched so callers can apply the wrapper

* `source` (starts with the matching OPEN tag, ends with CLOSE, and contains no
* internal close-tag variants), the original string is returned unchanged so
* internal open/close-tag variants), the original string is returned unchanged so
* `wrapUntrusted(wrapUntrusted(s, src), src) === wrapUntrusted(s, src)`.

@@ -35,0 +35,0 @@ */

@@ -21,4 +21,6 @@ /**

*/
const UNTRUSTED_CLOSE_TAG_VARIANT = /<\/untrusted-content\s*>/gi;
const UNTRUSTED_CLOSE_TAG_VARIANT = /<\/untrusted-content(?:\s[^>]*)?>/gi;
const ESCAPED_UNTRUSTED_CLOSE_TAG = '<\\/untrusted-content>';
const UNTRUSTED_OPEN_TAG_VARIANT = /<untrusted-content(?:\s[^>]*)?>/gi;
const ESCAPED_UNTRUSTED_OPEN_TAG = '<\\untrusted-content>';
const UNTRUSTED_ENVELOPE = /^<untrusted-content source="[^"]*">([\s\S]*)<\/untrusted-content>$/;

@@ -29,16 +31,24 @@ function escapeAttr(s) {

/**
* Rewrite every `</untrusted-content>` variant (case-insensitive, optional
* whitespace before `>`) inside `s` to a benign textual form, so an attacker
* who controls the wrapped content cannot terminate the envelope early.
* Rewrite every `</untrusted-content>` and `<untrusted-content …>` variant
* (case-insensitive, optional whitespace / attributes before `>`) inside `s`
* to a benign textual form, so an attacker who controls the wrapped content
* can neither terminate the envelope early nor spoof a nested open tag that a
* downstream parser could re-read as a fresh envelope. An LLM parsing the
* markup plausibly accepts attribute-bearing close forms such as
* `</untrusted-content foo>` — the matcher must cover them too.
*/
function escapeCloseTagSentinels(s) {
return s.replace(UNTRUSTED_CLOSE_TAG_VARIANT, ESCAPED_UNTRUSTED_CLOSE_TAG);
function escapeTagSentinels(s) {
return s
.replace(UNTRUSTED_OPEN_TAG_VARIANT, ESCAPED_UNTRUSTED_OPEN_TAG)
.replace(UNTRUSTED_CLOSE_TAG_VARIANT, ESCAPED_UNTRUSTED_CLOSE_TAG);
}
function unescapeCloseTagSentinels(s) {
return s.replaceAll(ESCAPED_UNTRUSTED_CLOSE_TAG, '</untrusted-content>');
function unescapeTagSentinels(s) {
return s
.replaceAll(ESCAPED_UNTRUSTED_OPEN_TAG, '<untrusted-content>')
.replaceAll(ESCAPED_UNTRUSTED_CLOSE_TAG, '</untrusted-content>');
}
/**
* Wrap a single untrusted string in an `<untrusted-content source="…">`
* envelope, escaping any embedded close-tag variant so the envelope cannot be
* broken out of.
* envelope, escaping any embedded open/close-tag variant so the envelope can
* neither be broken out of nor have a spoofed nested envelope planted inside.
*

@@ -50,3 +60,3 @@ * `undefined` and `null` are passed through untouched so callers can apply the wrapper

* `source` (starts with the matching OPEN tag, ends with CLOSE, and contains no
* internal close-tag variants), the original string is returned unchanged so
* internal open/close-tag variants), the original string is returned unchanged so
* `wrapUntrusted(wrapUntrusted(s, src), src) === wrapUntrusted(s, src)`.

@@ -61,9 +71,10 @@ */

const inner = text.slice(open.length, text.length - close.length);
if (!UNTRUSTED_CLOSE_TAG_VARIANT.test(inner)) {
UNTRUSTED_CLOSE_TAG_VARIANT.lastIndex = 0; // reset stateful /g regex
const hasVariant = UNTRUSTED_CLOSE_TAG_VARIANT.test(inner) || UNTRUSTED_OPEN_TAG_VARIANT.test(inner);
UNTRUSTED_CLOSE_TAG_VARIANT.lastIndex = 0; // reset stateful /g regexes
UNTRUSTED_OPEN_TAG_VARIANT.lastIndex = 0;
if (!hasVariant) {
return text;
}
UNTRUSTED_CLOSE_TAG_VARIANT.lastIndex = 0;
}
return `${open}${escapeCloseTagSentinels(text)}${close}`;
return `${open}${escapeTagSentinels(text)}${close}`;
}

@@ -80,3 +91,3 @@ /**

return text;
return unescapeCloseTagSentinels(match[1]);
return unescapeTagSentinels(match[1]);
}

@@ -83,0 +94,0 @@ /**

{
"name": "@mindstone/mcp-server-quickbooks",
"version": "0.4.1",
"version": "0.4.2",
"mcpName": "io.github.mindstone/mcp-server-quickbooks",

@@ -5,0 +5,0 @@ "description": "QuickBooks Online MCP server for Model Context Protocol hosts — invoices, bills, customers, vendors, accounts",

@@ -10,3 +10,3 @@ # @mindstone/mcp-server-quickbooks

- **Version:** [0.4.1](./CHANGELOG.md) · [npm](https://www.npmjs.com/package/@mindstone/mcp-server-quickbooks)
- **Version:** [0.4.2](./CHANGELOG.md) · [npm](https://www.npmjs.com/package/@mindstone/mcp-server-quickbooks)
- **Auth:** OAuth ([`QUICKBOOKS_REFRESH_TOKEN`](./server.json))

@@ -13,0 +13,0 @@ - **Tools:** [21](./src/tools/) (customers, vendors, invoices, bills, estimates, reports)