Repository: NethermindEth/warp (language: python)

Issue:
CRITICAL: Contract-to-contract calling must check bounds of return variables
We don't validate whether a Uint256 returned by an untrusted callee contract is within bounds.


Discussion / hints:

Fix patch:
diff --git a/src/passes/references/externalReturnReceiver.ts b/src/passes/references/externalReturnReceiver.ts
index 16fd8ff45..fb36c31ff 100644
--- a/src/passes/references/externalReturnReceiver.ts
+++ b/src/passes/references/externalReturnReceiver.ts
@@ -9,7 +9,7 @@ import {
 import { AST } from '../../ast/ast';
 import { ASTMapper } from '../../ast/mapper';
 import { cloneASTNode } from '../../utils/cloning';
-import { createIdentifier } from '../../utils/nodeTemplates';
+import { createExpressionStatement, createIdentifier } from '../../utils/nodeTemplates';
 import { isDynamicArray, safeGetNodeType } from '../../utils/nodeTypeProcessing';
 
 export class ExternalReturnReceiver extends ASTMapper {
@@ -52,9 +52,19 @@ export class ExternalReturnReceiver extends ASTMapper {
         ast.insertStatementAfter(node, statement);
         node.assignments = node.assignments.map((value) => (value === decl.id ? newId : value));
       });
+
+    node.vDeclarations.forEach((decl) => addOutputValidation(decl, ast));
   }
 }
 
+function addOutputValidation(decl: VariableDeclaration, ast: AST) {
+  const validationFunctionCall = ast
+    .getUtilFuncGen(decl)
+    .boundChecks.inputCheck.gen(decl, safeGetNodeType(decl, ast.inference), decl);
+  const validationStatement = createExpressionStatement(ast, validationFunctionCall);
+  ast.insertStatementAfter(decl, validationStatement);
+}
+
 function generateCopyStatement(
   decl: VariableDeclaration,
   ast: AST,


Test patch:
diff --git a/tests/behaviour/contracts/crossContractCalls/invalidOutput.sol b/tests/behaviour/contracts/crossContractCalls/invalidOutput.sol
new file mode 100644
index 000000000..16275f138
--- /dev/null
+++ b/tests/behaviour/contracts/crossContractCalls/invalidOutput.sol
@@ -0,0 +1,28 @@
+
+pragma solidity ^0.8.10;
+
+//SPDX-License-Identifier: MIT
+
+
+
+interface I{
+    function invalid() external returns (uint8);
+}
+
+
+contract A{
+    /// warp-cairo
+    /// DECORATOR(external)
+    /// func CURRENTFUNC()() -> (number : felt) {
+    ///     return (783495,);
+    /// }
+    function invalid() public returns (uint128) {
+    }
+}
+
+
+contract WARP{
+    function f(address addr) public returns (uint8){
+        return I(addr).invalid();
+    }
+}
diff --git a/tests/behaviour/expectations/behaviour.ts b/tests/behaviour/expectations/behaviour.ts
index 94a8698fd..f22779152 100644
--- a/tests/behaviour/expectations/behaviour.ts
+++ b/tests/behaviour/expectations/behaviour.ts
@@ -1948,6 +1948,23 @@ export const expectations = flatten(
             Expect.Simple('getS', [], ['1', '2', '3', '5']),
             Expect.Simple('getT', [], ['7', '11', '13']),
           ]),
+          // Force "A" contract deployment
+          File.Simple('invalidOutput', [], 'A'),
+          File.Simple(
+            'invalidOutput',
+            [
+              new Expect('f', [
+                [
+                  'f',
+                  ['address@tests/behaviour/contracts/crossContractCalls/invalidOutput.A'],
+                  null,
+                  '1',
+                  'Error: value out-of-bounds. Value must be less than 2**8',
+                ],
+              ]),
+            ],
+            'WARP',
+          ),
         ]),
         // covers nested mappings
         new Dir('daii', [