{"id":18852531,"url":"https://github.com/discue/somewhat-secure-insecure-fn-executor","last_synced_at":"2025-08-08T12:08:21.344Z","repository":{"id":205367670,"uuid":"714072038","full_name":"discue/somewhat-secure-insecure-fn-executor","owner":"discue","description":"Tries to mitigate risks of untrusted code by running it in an isolated environment","archived":false,"fork":false,"pushed_at":"2025-08-07T12:24:08.000Z","size":672,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-07T13:35:55.259Z","etag":null,"topics":["discue","isolate","js","untrusted-code"],"latest_commit_sha":null,"homepage":"https://www.discue.io","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/discue.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-11-03T21:21:40.000Z","updated_at":"2025-08-07T12:10:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"6d35d3ac-f68a-410c-89a9-596e185d4f9a","html_url":"https://github.com/discue/somewhat-secure-insecure-fn-executor","commit_stats":null,"previous_names":["discue/somewhat-secure-insecure-fn-executor"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/discue/somewhat-secure-insecure-fn-executor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discue%2Fsomewhat-secure-insecure-fn-executor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discue%2Fsomewhat-secure-insecure-fn-executor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discue%2Fsomewhat-secure-insecure-fn-executor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discue%2Fsomewhat-secure-insecure-fn-executor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/discue","download_url":"https://codeload.github.com/discue/somewhat-secure-insecure-fn-executor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discue%2Fsomewhat-secure-insecure-fn-executor/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269417542,"owners_count":24413384,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-08T02:00:09.200Z","response_time":72,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discue","isolate","js","untrusted-code"],"created_at":"2024-11-08T03:40:24.922Z","updated_at":"2025-08-08T12:08:21.314Z","avatar_url":"https://github.com/discue.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://www.discue.io/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cimg width=\"128\" src=\"https://www.discue.io/icons-fire-no-badge-square/web/icon-192.png\" alt=\"discue.io logo\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003cdiv align=\"center\"\u003e\n\n[![GitHub tag](https://img.shields.io/github/tag/discue/somewhat-secure-insecure-fn-executor?include_prereleases=\u0026sort=semver\u0026color=blue)](https://github.com/discue/somewhat-secure-insecure-fn-executor/releases/)\n[![Latest Stable Version](https://img.shields.io/npm/v/@discue/somewhat-secure-insecure-fn-executor.svg)](https://www.npmjs.com/package/@discue/somewhat-secure-insecure-fn-executor)\n[![License](https://img.shields.io/npm/l/@discue/somewhat-secure-insecure-fn-executor.svg)](https://www.npmjs.com/package/@discue/somewhat-secure-insecure-fn-executor)\n\u003cbr/\u003e\n[![NPM Downloads](https://img.shields.io/npm/dt/@discue/somewhat-secure-insecure-fn-executor.svg)](https://www.npmjs.com/package/@discue/somewhat-secure-insecure-fn-executor)\n[![NPM Downloads](https://img.shields.io/npm/dm/@discue/somewhat-secure-insecure-fn-executor.svg)](https://www.npmjs.com/package/@discue/somewhat-secure-insecure-fn-executor)\n\u003cbr/\u003e\n[![contributions - welcome](https://img.shields.io/badge/contributions-welcome-blue)](/CONTRIBUTING.md \"Go to contributions doc\")\n[![Made with Node.js](https://img.shields.io/badge/Node.js-\u003e=20-blue?logo=node.js\u0026logoColor=white)](https://nodejs.org \"Go to Node.js homepage\")\n\n\u003c/div\u003e\n\n# somewhat-secure-insecure-fn-executor\n**Don't let the funny title fool you**. There was definitely not enough testing to make sure this library can provide significant security for running untrusted code. What it **does** is to run untrusted code in an isolated environment with a minimum set of APIs to reduce the attack surface.\n\n**Generally:** You should not run untrusted code anywhere.\n\nAnd if you have to? Make sure you mitigate the risks on various levels:\n\n**Mitigations provided by this module:**\n- ✅ Allow only certain functions to be executed\n- ✅ Disable code generation via e.g. `eval` and `new Function()`\n- ✅ Limit access to I/O APIs like filesystem, socket, and http\n- ✅ Ensure global variables are immutable\n\n**Mitigations out-of-scope for this module:**\n- ❌ Do not run code that was was obfuscated\n- ❌ Run the sandbox with smallest possible set of permissions\n- ❌ Run the container of the sandbox with smallest possible set of permissions\n- ❌ Run the smallest number of services in the same account as the sandbox\n- more.. :)\n\n## Installation\n```bash\nnpm install @discue/somewhat-secure-insecure-fn-executor\n```\n\n## Constraints\n- Execution of `eval()`, `Function()`, `new Function()`, and `WebAssembly.*` is not allowed.\n- Return values of scripts must be `Primitives`, or `Objects`. `Functions`, `Symbols` and others are not allowed.\n- Built-in global variables cannot be changed.\n\n## API\nThe main export of the module is a function. It expects the following parameters:\n1. JS code as `string`\n2. Optional: An object to be passed to the script as `args`.\n\nThe return value is an object with the following properties:\n- **result**: The return value of the script. May be null. \n- **logs**: Logs captured during script execution\n- **durationMillis**: Duration of script execution in milliseconds\n- **ExecutionError**: Details about a captured error. May be null. \n\n```js\n/**\n * @typedef ExecutionResult\n * @property {any} [result] the return value of the given script\n * @property {Object\u003cString, Array\u003e} [logs] the logs captured during script execution\n * @property {number} durationMillis duration of the script execution in milliseconds\n * @property {ExecutionError} [error] error details captured during script execution\n */\n\n/**\n * @typedef ExecutionError\n * @property {string} [cause] the cause from the caputured error. May be null.\n * @property {number} [code] the code from the captured error. May be null.\n * @property {Array.\u003cstring\u003e} stack the stack trace from the captured error.\n * @property {string} message the message from the captured error. \n */\n\n/**\n * @param {string} script the script to run\n * @param {object} args arguments to pass to the script\n * @returns {ExecutionResult}\n */\nconst executor = require('@discue/somewhat-secure-insecure-fn-executor')\n\n```\n\n## Examples\n### Simple script execution\nThe executor runs the script `return 1+1` and returns the result of the calculation. \n```js\nconst executor = require('@discue/somewhat-secure-insecure-fn-executor')\nconst result = await executor('return 1+1')\n// {\n//   \"result\": 2,\n//   \"logs\": {\n//     \"log\": [],\n//     \"error\": [],\n//     \"warn\": [],\n//     \"info\": []\n//   },\n//   \"durationMillis\": 0\n// }\n```\n\n### Execution with parameters\nTo pass parameters to the script call the executor function with an object as second parameter. The parameter object will be available as `args` for execution of your script.\n```js\nconst executor = require('@discue/somewhat-secure-insecure-fn-executor')\nconst result = await executor('return args.a + args.b', { a: 1, b: 3 })\n// {\n//   \"result\": 4,\n//   \"logs\": {\n//     \"log\": [],\n//     \"error\": [],\n//     \"warn\": [],\n//     \"info\": []\n//   },\n//   \"durationMillis\": 0\n// }\n```\n\n### Node globals are not available\nThe user provided scripts are executed in a dedicated v8 environment. NodeJS globals are not available in this context. \n\n```js\nconst executor = require('@discue/somewhat-secure-insecure-fn-executor')\nconst result = await executor('process.exit(0)')\n// {\n//   \"logs\": {\n//     \"log\": [],\n//     \"error\": [\n//       \"ReferenceError: process is not defined\"\n//     ],\n//     \"warn\": [],\n//     \"info\": []\n//   },\n//   \"error\": {\n//     \"message\": \"process is not defined\",\n//     \"stack\": [\n//       \"ReferenceError: process is not defined\",\n//       \"at userSuppliedScript (file:///user-supplied-script.js:1:1)\",\n//       \"at runtime.js:38:24\"\n//     ]\n//   },\n//   \"durationMillis\": 1\n// }\n```\n\n### Error handling\nAny exceptions occuring during script execution are captured and returned to the caller. The `error` object contains details of the exception: `cause`, `code`, `message`, and `stack`.\n```js\nconst executor = require('@discue/somewhat-secure-insecure-fn-executor')\nconst result = await executor('eval(1+1)')\n// {\n//   \"logs\": {\n//     \"log\": [],\n//     \"error\": [\n//       \"Error: \\\"eval\\\" is not allowed in this context.\"\n//     ],\n//     \"warn\": [],\n//     \"info\": []\n//   },\n//   \"error\": {\n//     \"message\": \"\\\"eval\\\" is not allowed in this context.\",\n//     \"stack\": [\n//       \"Error: \\\"eval\\\" is not allowed in this context.\",\n//       \"at global.\u003ccomputed\u003e (file:///code-generation.js:1:19)\",\n//       \"at userSuppliedScript (file:///user-supplied-script.js:2:9)\",\n//       \"at runtime.js:38:24\"\n//     ]\n//   },\n//   \"durationMillis\": 0\n// }\n```\n\n## License\n[MIT](https://choosealicense.com/licenses/mit/)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscue%2Fsomewhat-secure-insecure-fn-executor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiscue%2Fsomewhat-secure-insecure-fn-executor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscue%2Fsomewhat-secure-insecure-fn-executor/lists"}