-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Running untrusted Javascript in SmartWeave contracts #77
Comments
I'll add here that anything utilizing the foreign call protocol (which will hopefully be all SmartWeave token contracts in the future) would be at risk of this without a sandbox environment because users would be able to introduce any code into the execution path of the other contracts. Technically users could whitelist the contracts that other contracts can read from, however, this naturally puts a large limitation on who can interact with what. |
What about Quickjs? |
Here's a tiny solution for sandboxing contracts on Node.js (please test before using) - diff --git a/src/contract-load.ts b/src/contract-load.ts
index 35c74fc..b700e5a 100644
--- a/src/contract-load.ts
+++ b/src/contract-load.ts
@@ -4,6 +4,7 @@ import { getTag, normalizeContractSource } from './utils';
import { ContractHandler } from './contract-step';
import { SmartWeaveGlobal } from './smartweave-global';
import BigNumber from 'bignumber.js';
+import * as vm from "vm";
/**
* Loads the contract source, initial state and other parameters
@@ -65,11 +66,19 @@ export function createContractExecutionEnvironment(
contractOwner: string,
) {
const returningSrc = normalizeContractSource(contractSrc);
+
const swGlobal = new SmartWeaveGlobal(arweave, { id: contractId, owner: contractOwner });
- const getContractFunction = new Function(returningSrc); // eslint-disable-line
+ const getContractFunction = async (state, interaction) => {
+ let context = vm.createContext({ handle: null, swGlobal, BigNumber, clarity });
+ vm.runInContext(returningSrc, context, {
+ timeout: 10000,
+ });
+
+ return await context.handle(state, interaction);
+ }
return {
- handler: getContractFunction(swGlobal, BigNumber, clarity) as ContractHandler,
+ handler: getContractFunction as ContractHandler,
swGlobal,
};
}
diff --git a/src/utils.ts b/src/utils.ts
index 54e1dbe..3823760 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -97,11 +97,9 @@ export function normalizeContractSource(contractSrc: string): string {
.replace(/}\s*\)\s*\(\)\s*;/g, '');
return `
- const [SmartWeave, BigNumber, clarity] = arguments;
clarity.SmartWeave = SmartWeave;
class ContractError extends Error { constructor(message) { super(message); this.name = \'ContractError\' } };
function ContractAssert(cond, message) { if (!cond) throw new ContractError(message) };
${contractSrc};
- return handle;
`;
} For browsers, the first thing that I can think of is using Web Workers and falling back to a QuickJS WASM interpreter. |
Hey @marcelsud @littledivy, thanks for the time you've put into this! As a community we've had a few calls on this topic and we're just working out what direction we should take this in. A lot of it seems to be going towards using WASM as a more portable and sandboxed solution. Feel free to discuss more with me and the community in the dev Discord: https://discord.gg/p8V3QC7J |
Hey,
I think we're going to need a way to run any JavaScript safely. This is going to be needed for certain things that are coming into the ecosystem such as AMM's. If we are to run random PST contracts in the browser we need to sandbox the code so it's 100% harmless.
I wanted this to be the start of the discussion on the topic. I have a few ideas so far. Sandboxing can be done in two ways:
Let me know your thoughts on this.
The text was updated successfully, but these errors were encountered: