diff --git a/.socket/blob/07fe19aac4aab8d78c9c1b6eefdcbd9af489cecacbebb06224a1f12de48a93a9 b/.socket/blob/07fe19aac4aab8d78c9c1b6eefdcbd9af489cecacbebb06224a1f12de48a93a9 new file mode 100644 index 0000000..e6bf675 --- /dev/null +++ b/.socket/blob/07fe19aac4aab8d78c9c1b6eefdcbd9af489cecacbebb06224a1f12de48a93a9 @@ -0,0 +1,385 @@ +// Socket Community Patch: https://socket.dev +// Date: Thu, 08 Jan 2026 20:18:07 GMT +// For more information see https://socket.dev/patch/b91859e2-ca75-4fe1-8892-fdfd677cfd47 +// This file includes modifications made by Socket, Inc. on Thu, 08 Jan 2026; these modifications are called the "Patch". In some cases, Socket may be required to make the Patch available to you under specific terms, or may be prohibited from restricting certain rights you may have. For example, the terms of another applicable license may require Socket to make the Patch available under specific terms. In those cases, the Patch is made available to you under the required terms, and Socket does not seek to restrict your rights relative to the Patch where prohibited. In all other cases, the Patch is available to you exclusively under the PolyForm Shield License 1.0.0 (https://polyformproject.org/licenses/shield/1.0.0/). The Patch was distributed by Socket with additional information concerning licensing, attribution, and limitation of liability which may be relevant to you and your use of the Patch. As far as the law allows, the Patch and the software including the patch come as is, without any warranty or condition, and Socket will not be liable to you for any damages arising out of the applicable license terms or the use or nature of the Patch or the software including the patch, under any kind of legal claim. +// Original License: MIT + +const tar = require('tar-stream') +const pump = require('pump') +const mkdirp = require('mkdirp-classic') +const fs = require('fs') +const path = require('path') + +const win32 = process.platform === 'win32' + +exports.pack = function pack (cwd, opts) { + if (!cwd) cwd = '.' + if (!opts) opts = {} + + const xfs = opts.fs || fs + const ignore = opts.ignore || opts.filter || noop + const mapStream = opts.mapStream || echo + const statNext = statAll(xfs, opts.dereference ? xfs.stat : xfs.lstat, cwd, ignore, opts.entries, opts.sort) + const strict = opts.strict !== false + const umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask() + const pack = opts.pack || tar.pack() + const finish = opts.finish || noop + + let map = opts.map || noop + let dmode = typeof opts.dmode === 'number' ? opts.dmode : 0 + let fmode = typeof opts.fmode === 'number' ? opts.fmode : 0 + + if (opts.strip) map = strip(map, opts.strip) + + if (opts.readable) { + dmode |= parseInt(555, 8) + fmode |= parseInt(444, 8) + } + if (opts.writable) { + dmode |= parseInt(333, 8) + fmode |= parseInt(222, 8) + } + + onnextentry() + + function onsymlink (filename, header) { + xfs.readlink(path.join(cwd, filename), function (err, linkname) { + if (err) return pack.destroy(err) + header.linkname = normalize(linkname) + pack.entry(header, onnextentry) + }) + } + + function onstat (err, filename, stat) { + if (err) return pack.destroy(err) + if (!filename) { + if (opts.finalize !== false) pack.finalize() + return finish(pack) + } + + if (stat.isSocket()) return onnextentry() // tar does not support sockets... + + let header = { + name: normalize(filename), + mode: (stat.mode | (stat.isDirectory() ? dmode : fmode)) & umask, + mtime: stat.mtime, + size: stat.size, + type: 'file', + uid: stat.uid, + gid: stat.gid + } + + if (stat.isDirectory()) { + header.size = 0 + header.type = 'directory' + header = map(header) || header + return pack.entry(header, onnextentry) + } + + if (stat.isSymbolicLink()) { + header.size = 0 + header.type = 'symlink' + header = map(header) || header + return onsymlink(filename, header) + } + + // TODO: add fifo etc... + + header = map(header) || header + + if (!stat.isFile()) { + if (strict) return pack.destroy(new Error('unsupported type for ' + filename)) + return onnextentry() + } + + const entry = pack.entry(header, onnextentry) + const rs = mapStream(xfs.createReadStream(path.join(cwd, filename), { start: 0, end: header.size > 0 ? header.size - 1 : header.size }), header) + + rs.on('error', function (err) { // always forward errors on destroy + entry.destroy(err) + }) + + pump(rs, entry) + } + + function onnextentry (err) { + if (err) return pack.destroy(err) + statNext(onstat) + } + + return pack +} + +function head (list) { + return list.length ? list[list.length - 1] : null +} + +function processGetuid () { + return process.getuid ? process.getuid() : -1 +} + +function processUmask () { + return process.umask ? process.umask() : 0 +} + +exports.extract = function extract (cwd, opts) { + if (!cwd) cwd = '.' + if (!opts) opts = {} + + cwd = path.resolve(cwd) + + const xfs = opts.fs || fs + const ignore = opts.ignore || opts.filter || noop + const mapStream = opts.mapStream || echo + const own = opts.chown !== false && !win32 && processGetuid() === 0 + const extract = opts.extract || tar.extract() + const stack = [] + const now = new Date() + const umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask() + const strict = opts.strict !== false + + let map = opts.map || noop + let dmode = typeof opts.dmode === 'number' ? opts.dmode : 0 + let fmode = typeof opts.fmode === 'number' ? opts.fmode : 0 + + if (opts.strip) map = strip(map, opts.strip) + + if (opts.readable) { + dmode |= parseInt(555, 8) + fmode |= parseInt(444, 8) + } + if (opts.writable) { + dmode |= parseInt(333, 8) + fmode |= parseInt(222, 8) + } + + extract.on('entry', onentry) + + if (opts.finish) extract.on('finish', opts.finish) + + return extract + + function onentry (header, stream, next) { + header = map(header) || header + header.name = normalize(header.name) + + const name = path.join(cwd, path.join('/', header.name)) + + if (ignore(name, header)) { + stream.resume() + return next() + } + + if (header.type === 'directory') { + stack.push([name, header.mtime]) + return mkdirfix(name, { + fs: xfs, + own, + uid: header.uid, + gid: header.gid, + mode: header.mode + }, stat) + } + + const dir = path.dirname(name) + + validate(xfs, dir, path.join(cwd, '.'), function (err, valid) { + if (err) return next(err) + if (!valid) return next(new Error(dir + ' is not a valid path')) + + mkdirfix(dir, { + fs: xfs, + own, + uid: header.uid, + gid: header.gid, + // normally, the folders with rights and owner should be part of the TAR file + // if this is not the case, create folder for same user as file and with + // standard permissions of 0o755 (rwxr-xr-x) + mode: 0o755 + }, function (err) { + if (err) return next(err) + + switch (header.type) { + case 'file': return onfile() + case 'link': return onlink() + case 'symlink': return onsymlink() + } + + if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')')) + + stream.resume() + next() + }) + }) + + function stat (err) { + if (err) return next(err) + utimes(name, header, function (err) { + if (err) return next(err) + if (win32) return next() + chperm(name, header, next) + }) + } + + function onsymlink () { + if (win32) return next() // skip symlinks on win for now before it can be tested + xfs.unlink(name, function () { + const dst = path.resolve(path.dirname(name), header.linkname) + if (!inCwd(dst)) return next(new Error(name + ' is not a valid symlink')) + + xfs.symlink(header.linkname, name, stat) + }) + } + + function onlink () { + if (win32) return next() // skip links on win for now before it can be tested + xfs.unlink(name, function () { + const dst = path.join(cwd, path.join('/', header.linkname)) + + xfs.link(dst, name, function (err) { + if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) { + stream = xfs.createReadStream(dst) + return onfile() + } + + stat(err) + }) + }) + } + + function inCwd (dst) { + return dst.startsWith(cwd) + } + + function onfile () { + const ws = xfs.createWriteStream(name) + const rs = mapStream(stream, header) + + ws.on('error', function (err) { // always forward errors on destroy + rs.destroy(err) + }) + + pump(rs, ws, function (err) { + if (err) return next(err) + ws.on('close', stat) + }) + } + } + + function utimesParent (name, cb) { // we just set the mtime on the parent dir again everytime we write an entry + let top + while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop() + if (!top) return cb() + xfs.utimes(top[0], now, top[1], cb) + } + + function utimes (name, header, cb) { + if (opts.utimes === false) return cb() + + if (header.type === 'directory') return xfs.utimes(name, now, header.mtime, cb) + if (header.type === 'symlink') return utimesParent(name, cb) // TODO: how to set mtime on link? + + xfs.utimes(name, now, header.mtime, function (err) { + if (err) return cb(err) + utimesParent(name, cb) + }) + } + + function chperm (name, header, cb) { + const link = header.type === 'symlink' + + /* eslint-disable n/no-deprecated-api */ + const chmod = link ? xfs.lchmod : xfs.chmod + const chown = link ? xfs.lchown : xfs.chown + /* eslint-enable n/no-deprecated-api */ + + if (!chmod) return cb() + + const mode = (header.mode | (header.type === 'directory' ? dmode : fmode)) & umask + + if (chown && own) chown.call(xfs, name, header.uid, header.gid, onchown) + else onchown(null) + + function onchown (err) { + if (err) return cb(err) + if (!chmod) return cb() + chmod.call(xfs, name, mode, cb) + } + } + + function mkdirfix (name, opts, cb) { + // when mkdir is called on an existing directory, the permissions + // will be overwritten (?), to avoid this we check for its existance first + xfs.stat(name, function (err) { + if (!err) return cb(null) + if (err.code !== 'ENOENT') return cb(err) + mkdirp(name, { fs: opts.fs, mode: opts.mode }, function (err, made) { + if (err) return cb(err) + chperm(name, opts, cb) + }) + }) + } +} + +function validate (fs, name, root, cb) { + if (name === root) return cb(null, true) + fs.lstat(name, function (err, st) { + if (err && err.code === 'ENOENT') return validate(fs, path.join(name, '..'), root, cb) + else if (err) return cb(err) + cb(null, st.isDirectory()) + }) +} + +function noop () {} + +function echo (name) { + return name +} + +function normalize (name) { + return win32 ? name.replace(/\\/g, '/').replace(/[:?<>|]/g, '_') : name +} + +function statAll (fs, stat, cwd, ignore, entries, sort) { + if (!entries) entries = ['.'] + const queue = entries.slice(0) + + return function loop (callback) { + if (!queue.length) return callback(null) + + const next = queue.shift() + const nextAbs = path.join(cwd, next) + + stat.call(fs, nextAbs, function (err, stat) { + // ignore errors if the files were deleted while buffering + if (err) return callback(entries.indexOf(next) === -1 && err.code === 'ENOENT' ? null : err) + + if (!stat.isDirectory()) return callback(null, next, stat) + + fs.readdir(nextAbs, function (err, files) { + if (err) return callback(err) + + if (sort) files.sort() + + for (let i = 0; i < files.length; i++) { + if (!ignore(path.join(cwd, next, files[i]))) queue.push(path.join(next, files[i])) + } + + callback(null, next, stat) + }) + }) + } +} + +function strip (map, level) { + return function (header) { + header.name = header.name.split('/').slice(level).join('/') + + const linkname = header.linkname + if (linkname && (header.type === 'link' || path.isAbsolute(linkname))) { + header.linkname = linkname.split('/').slice(level).join('/') + } + + return map(header) + } +} diff --git a/.socket/manifest.json b/.socket/manifest.json new file mode 100644 index 0000000..7bf8d14 --- /dev/null +++ b/.socket/manifest.json @@ -0,0 +1,27 @@ +{ + "patches": { + "pkg:npm/tar-fs@3.0.4": { + "uuid": "b91859e2-ca75-4fe1-8892-fdfd677cfd47", + "exportedAt": "Thu, 08 Jan 2026 20:18:08 GMT", + "files": { + "package/index.js": { + "beforeHash": "1263007ac16293589727bd73922aea714f42bd08c19cdb7b6ba409515ff0b73f", + "afterHash": "07fe19aac4aab8d78c9c1b6eefdcbd9af489cecacbebb06224a1f12de48a93a9" + } + }, + "vulnerabilities": { + "GHSA-pq67-2wwv-3xjx": { + "cves": [ + "CVE-2024-12905" + ], + "summary": "tar-fs Vulnerable to Link Following and Path Traversal via Extracting a Crafted tar File", + "severity": "HIGH", + "description": "An Improper Link Resolution Before File Access (\"Link Following\") and Improper Limitation of a Pathname to a Restricted Directory (\"Path Traversal\"). This vulnerability occurs when extracting a maliciously crafted tar file, which can result in unauthorized file writes or overwrites outside the intended extraction directory. The issue is associated with index.js in the tar-fs package.\n\nThis issue affects tar-fs: from 0.0.0 before 1.16.4, from 2.0.0 before 2.1.2, from 3.0.0 before 3.0.7.\n\n### PoC\n```javascript\n// Create a writable stream to extract the tar content\nconst extractStream = tarfs.extract('/', {\n // We can ignore the file type checks to allow the extraction of the malicious file\n ignore: (name) => false,\n});\n\n// Create a tar stream\nconst tarStream = tarfs.pack().on('error', (err) => {\n throw err;\n});\n\n// Append the malicious entry to the tar stream\ntarStream.entry({ name: '/flag.txt', mode: 0o644 }, Buffer.from('This is a flag!'));\n\n// Finalize the tar stream\ntarStream.finalize();\n\n// Pipe the tar stream into the extract stream\ntarStream.pipe(extractStream);\n```" + } + }, + "description": "", + "license": "MIT", + "tier": "free" + } + } +} \ No newline at end of file diff --git a/mcp_modules/backlinks/package.json b/mcp_modules/backlinks/package.json index 866dbac..bef6f22 100644 --- a/mcp_modules/backlinks/package.json +++ b/mcp_modules/backlinks/package.json @@ -7,7 +7,9 @@ "scripts": { "test": "mocha test/**/*.test.js", "lint": "eslint src/ test/ --ext .js", - "lint:fix": "eslint src/ test/ --ext .js --fix" + "lint:fix": "eslint src/ test/ --ext .js --fix", + "postinstall": "npx @socketsecurity/socket-patch apply --silent --ecosystems npm", + "dependencies": "npx @socketsecurity/socket-patch apply --silent --ecosystems npm" }, "keywords": [ "mcp",