├── docs ├── static │ ├── .nojekyll │ └── img │ │ ├── html.png │ │ ├── scout.png │ │ ├── favicon.ico │ │ ├── stellar.png │ │ ├── aleph-zero.png │ │ ├── docusaurus.png │ │ ├── html-report.png │ │ ├── vscode-extension.png │ │ ├── web3-foundation.png │ │ ├── scout-social-card.jpg │ │ ├── scout-soroban-html.jpg │ │ ├── github-action-output.jpg │ │ └── docusaurus-social-card.jpg ├── babel.config.js ├── blog │ ├── 2021-08-26-welcome │ │ ├── docusaurus-plushie-banner.jpeg │ │ └── index.md │ ├── 2019-05-28-first-blog-post.md │ ├── authors.yml │ └── 2021-08-01-mdx-blog-post.mdx ├── src │ ├── pages │ │ ├── markdown-page.md │ │ ├── index.module.css │ │ ├── about.js │ │ └── index.tsx │ ├── components │ │ └── HomepageFeatures │ │ │ └── styles.module.css │ └── css │ │ └── custom.css ├── docs │ ├── precision-and-recall │ │ └── README.md │ ├── detectors │ │ ├── 7-avoid-core-mem-forget.md │ │ ├── 12-soroban-version.md │ │ ├── README.md │ │ ├── 15-assert-violation.md │ │ ├── 2-unsafe-unwrap.md │ │ ├── 3-unsafe-expect.md │ │ ├── 8-set-contract-storage.md │ │ ├── 21-incorrect-exponentiation.md │ │ ├── 1-divide-before-multiply.md │ │ ├── 11-dos-unbounded-operation.md │ │ ├── 20-zero-or-test-address.md │ │ ├── 10-avoid-unsafe-block.md │ │ ├── 19-unsafe-map-get.md │ │ ├── 14-iterators-over-indexing.md │ │ ├── 9-avoid-panic-error.md │ │ └── 5-insufficiently-random-values.md │ ├── architecture.md │ ├── vscode-extension.md │ └── vulnerabilities │ │ ├── 4-overflow-check.md │ │ ├── 7-avoid-core-mem-forget.md │ │ └── 12-soroban-version.md ├── tsconfig.json ├── .gitignore ├── sidebars.js └── package.json ├── CHANGELOG.md ├── assets ├── image.png ├── scout.png └── vscode-extension.png ├── detectors ├── rust-toolchain ├── README.md ├── .cargo │ └── config.toml ├── unsafe-expect │ └── Cargo.toml ├── unsafe-unwrap │ └── Cargo.toml ├── assert-violation │ └── Cargo.toml ├── avoid-panic-error │ └── Cargo.toml ├── avoid-unsafe-block │ └── Cargo.toml ├── unused-return-enum │ └── Cargo.toml ├── avoid-core-mem-forget │ └── Cargo.toml ├── divide-before-multiply │ └── Cargo.toml ├── dos-unbounded-operation │ └── Cargo.toml ├── incorrect-exponentiation │ └── Cargo.toml ├── overflow-check │ └── Cargo.toml ├── unrestricted-transfer-from │ └── Cargo.toml ├── insufficiently-random-values │ └── Cargo.toml ├── zero-address │ └── Cargo.toml ├── unsafe-map-get │ └── Cargo.toml ├── dos-unexpected-revert-with-vector │ └── Cargo.toml ├── set-contract-storage │ └── Cargo.toml ├── iterators-over-indexing │ └── Cargo.toml ├── integer-overflow-or-underflow │ └── Cargo.toml ├── unprotected-mapping-operation │ └── Cargo.toml ├── soroban-version │ └── Cargo.toml ├── vec-could-be-mapping │ └── Cargo.toml ├── unprotected-update-current-contract-wasm │ └── Cargo.toml └── Cargo.toml ├── utils ├── rust-toolchain ├── Cargo.toml └── src │ └── lib.rs ├── test-cases ├── zero-address │ └── zero-address-1 │ │ ├── remediated-example │ │ ├── rust-toolchain │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ ├── rust-toolchain │ │ └── Cargo.toml ├── vec-could-be-mapping │ └── vec-could-be-mapping-1 │ │ ├── remediated-example │ │ ├── rust-toolchain │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ ├── rust-toolchain │ │ └── Cargo.toml ├── overflow-check │ └── overflow-check-1 │ │ ├── remediated-example │ │ ├── src │ │ │ └── lib.rs │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ ├── src │ │ └── lib.rs │ │ └── Cargo.toml ├── soroban-version │ ├── soroban-version-1 │ │ ├── remediated-example │ │ │ ├── src │ │ │ │ └── lib.rs │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── src │ │ │ └── lib.rs │ │ │ └── Cargo.toml │ └── Cargo.toml ├── avoid-panic-error │ ├── avoid-panic-error-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ └── Cargo.toml ├── README.md ├── unsafe-expect │ ├── unsafe-expect-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ ├── unsafe-expect-2 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ ├── unsafe-expect-3 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ ├── unsafe-expect-4 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ ├── unsafe-expect-5 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ └── Cargo.toml ├── unsafe-unwrap │ ├── unsafe-unwrap-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── unsafe-unwrap-2 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── unsafe-unwrap-3 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── unsafe-unwrap-4 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── unsafe-unwrap-5 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── unsafe-unwrap-6 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── assert-violation │ ├── assert-violation-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── unsafe-map-get │ ├── unsafe-map-get-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── avoid-unsafe-block │ ├── avoid-unsafe-block-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── unused-return-enum │ ├── unused-return-enum-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── unused-return-enum-2 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── set-contract-storage │ ├── set-contract-storage-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── set-contract-storage-2 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── set-contract-storage-3 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── set-contract-storage-4 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── avoid-core-mem-forget │ ├── avoid-core-mem-forget-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── divide-before-multiply │ ├── divide-before-multiply-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── divide-before-multiply-2 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── divide-before-multiply-3 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── dos-unbounded-operation │ ├── dos-unbounded-operation-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── dos-unbounded-operation-2 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── dos-unbounded-operation-3 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── incorrect-exponentiation │ ├── incorrect-exponentiation-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── iterators-over-indexing │ ├── iterators-over-indexing-1 │ │ ├── remediated-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── unrestricted-transfer-from │ ├── unrestricted-transfer-from-1 │ │ ├── vulnerable-example │ │ │ └── Cargo.toml │ │ └── remediated-example │ │ │ └── Cargo.toml │ └── Cargo.toml ├── integer-overflow-or-underflow │ ├── integer-overflow-or-underflow-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── integer-overflow-or-underflow-2 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── integer-overflow-or-underflow-3 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── integer-overflow-or-underflow-4 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── integer-overflow-or-underflow-5 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── Cargo.toml ├── insufficiently-random-values │ ├── insufficiently-random-values-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ └── Cargo.toml ├── unprotected-mapping-operation │ ├── unprotected-mapping-operation-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ ├── unprotected-mapping-operation-2 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ └── Cargo.toml ├── dos-unexpected-revert-with-vector │ ├── dos-unexpected-revert-with-vector-1 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ ├── dos-unexpected-revert-with-vector-2 │ │ ├── remediated-example │ │ │ └── Cargo.toml │ │ └── vulnerable-example │ │ │ └── Cargo.toml │ └── Cargo.toml └── unprotected-update-current-contract-wasm │ ├── unprotected-update-current-contract-wasm-1 │ ├── remediated-example │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── vulnerable-example │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs │ ├── Cargo.toml │ └── unprotected-update-current-contract-wasm-2 │ ├── remediated-example │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ └── vulnerable-example │ ├── Cargo.toml │ └── src │ └── lib.rs ├── .vscode ├── extensions.json └── settings.json ├── templates ├── detector │ ├── late-lint │ │ └── Cargo.toml │ └── early-lint │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs └── test-case │ ├── Cargo.toml │ └── src │ └── lib.rs ├── .editorconfig ├── Makefile ├── .github ├── ISSUE_TEMPLATE │ └── project-tasks.md └── workflows │ └── deploy-docs.yml ├── LICENSE ├── .gitignore └── scripts ├── run-fmt.py └── run-udeps.py /docs/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | -------------------------------------------------------------------------------- /assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/assets/image.png -------------------------------------------------------------------------------- /assets/scout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/assets/scout.png -------------------------------------------------------------------------------- /docs/static/img/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/html.png -------------------------------------------------------------------------------- /docs/static/img/scout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/scout.png -------------------------------------------------------------------------------- /assets/vscode-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/assets/vscode-extension.png -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/static/img/stellar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/stellar.png -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/static/img/aleph-zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/aleph-zero.png -------------------------------------------------------------------------------- /docs/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/docusaurus.png -------------------------------------------------------------------------------- /docs/static/img/html-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/html-report.png -------------------------------------------------------------------------------- /detectors/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2024-07-11" 3 | components = ["llvm-tools-preview", "rustc-dev"] 4 | -------------------------------------------------------------------------------- /utils/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2024-07-11" 3 | components = ["llvm-tools-preview", "rustc-dev"] 4 | -------------------------------------------------------------------------------- /docs/static/img/vscode-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/vscode-extension.png -------------------------------------------------------------------------------- /docs/static/img/web3-foundation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/web3-foundation.png -------------------------------------------------------------------------------- /docs/static/img/scout-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/scout-social-card.jpg -------------------------------------------------------------------------------- /docs/static/img/scout-soroban-html.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/scout-soroban-html.jpg -------------------------------------------------------------------------------- /docs/static/img/github-action-output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/github-action-output.jpg -------------------------------------------------------------------------------- /docs/static/img/docusaurus-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/static/img/docusaurus-social-card.jpg -------------------------------------------------------------------------------- /docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoinFabrik/scout-soroban/HEAD/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg -------------------------------------------------------------------------------- /docs/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /test-cases/zero-address/zero-address-1/remediated-example/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2023-09-29" 3 | components = ["llvm-tools-preview", "rustc-dev"] 4 | -------------------------------------------------------------------------------- /test-cases/zero-address/zero-address-1/vulnerable-example/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2023-09-29" 3 | components = ["llvm-tools-preview", "rustc-dev"] 4 | -------------------------------------------------------------------------------- /test-cases/vec-could-be-mapping/vec-could-be-mapping-1/remediated-example/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2023-09-29" 3 | components = ["llvm-tools-preview", "rustc-dev"] 4 | -------------------------------------------------------------------------------- /test-cases/vec-could-be-mapping/vec-could-be-mapping-1/vulnerable-example/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2023-09-29" 3 | components = ["llvm-tools-preview", "rustc-dev"] 4 | -------------------------------------------------------------------------------- /detectors/README.md: -------------------------------------------------------------------------------- 1 | # Detectors 2 | 3 | For each detector linter in this folder, find a detailed explanation in our [documentation webpage](https://coinfabrik.github.io/scout-soroban/docs/detectors). -------------------------------------------------------------------------------- /docs/docs/precision-and-recall/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Precision and recall 6 | 7 | This section outlines the tasks we perform to enhance the overall quality of Scout. -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "editorconfig.editorconfig", 4 | "esbenp.prettier-vscode", 5 | "dbaeumer.vscode-eslint", 6 | "rust-lang.rust-analyzer" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.rustfmt.extraArgs": ["+nightly"], 3 | "rust-analyzer.showUnlinkedFileNotification": false, 4 | "rust-analyzer.linkedProjects": [ 5 | "apps/cargo-scout-audit/Cargo.toml", 6 | "detectors/Cargo.toml" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /detectors/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.aarch64-apple-darwin] 2 | linker = "dylint-link" 3 | 4 | [target.x86_64-apple-darwin] 5 | linker = "dylint-link" 6 | 7 | [target.x86_64-unknown-linux-gnu] 8 | linker = "dylint-link" 9 | 10 | [target.x86_64-pc-windows-msvc] 11 | linker = "dylint-link" 12 | -------------------------------------------------------------------------------- /utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "utils" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | if_chain = "=1.0.2" 8 | clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "51a1cf0" } 9 | 10 | [package.metadata.rust-analyzer] 11 | rustc_private = true 12 | -------------------------------------------------------------------------------- /test-cases/overflow-check/overflow-check-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl}; 4 | 5 | #[contract] 6 | pub struct Contract; 7 | 8 | #[contractimpl] 9 | impl Contract { 10 | // Empty contract - vulnerability is in the Cargo.toml 11 | } 12 | -------------------------------------------------------------------------------- /test-cases/overflow-check/overflow-check-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl}; 4 | 5 | #[contract] 6 | pub struct Contract; 7 | 8 | #[contractimpl] 9 | impl Contract { 10 | // Empty contract - vulnerability is in the Cargo.toml 11 | } 12 | -------------------------------------------------------------------------------- /test-cases/soroban-version/soroban-version-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl}; 4 | 5 | #[contract] 6 | pub struct Contract; 7 | 8 | #[contractimpl] 9 | impl Contract { 10 | // Empty contract - vulnerability is in the Cargo.toml 11 | } 12 | -------------------------------------------------------------------------------- /test-cases/soroban-version/soroban-version-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl}; 4 | 5 | #[contract] 6 | pub struct Contract; 7 | 8 | #[contractimpl] 9 | impl Contract { 10 | // Empty contract - vulnerability is in the Cargo.toml 11 | } 12 | -------------------------------------------------------------------------------- /utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | mod function_call_visitor; 4 | pub use function_call_visitor::FunctionCallVisitor; 5 | 6 | mod soroban_utils; 7 | pub use soroban_utils::*; 8 | 9 | mod lint_utils; 10 | pub use lint_utils::*; 11 | 12 | mod constant_analyzer; 13 | pub use constant_analyzer::*; 14 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /test-cases/avoid-panic-error/avoid-panic-error-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-panic-error-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [features] 13 | testutils = ["soroban-sdk/testutils"] 14 | -------------------------------------------------------------------------------- /test-cases/avoid-panic-error/avoid-panic-error-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-panic-error-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [features] 13 | testutils = ["soroban-sdk/testutils"] 14 | -------------------------------------------------------------------------------- /detectors/unsafe-expect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/unsafe-unwrap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/assert-violation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "assert-violation" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/avoid-panic-error/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-panic-error" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/avoid-unsafe-block/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-unsafe-block" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/unused-return-enum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unused-return-enum" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/avoid-core-mem-forget/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-core-mem-forget" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /templates/detector/late-lint/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "detector-name" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | dylint_linting = { workspace = true } 11 | if_chain = { workspace = true } 12 | 13 | scout-audit-clippy-utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true -------------------------------------------------------------------------------- /detectors/divide-before-multiply/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "divide-before-multiply" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/dos-unbounded-operation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unbounded-operation" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/incorrect-exponentiation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "incorrect-exponentiation" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/overflow-check/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "overflow-check" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | toml = "0.8.8" 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /templates/detector/early-lint/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "detector-name" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | dylint_linting = { workspace = true } 11 | if_chain = { workspace = true } 12 | 13 | scout-audit-clippy-utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true -------------------------------------------------------------------------------- /detectors/unrestricted-transfer-from/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unrestricted-transfer-from" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /test-cases/README.md: -------------------------------------------------------------------------------- 1 | # Test Cases 2 | 3 | For each [Vulnerability Class](https://coinfabrik.github.io/scout-soroban/docs/vulnerabilities#vulnerability-classes) listed in our documentation, you will find different test cases in this repository. 4 | 5 | Check our [Contribution Guideline](https://coinfabrik.github.io/scout-soroban/docs/contribute) for instructions on how to add new test cases for Scout. 6 | -------------------------------------------------------------------------------- /detectors/insufficiently-random-values/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "insufficiently-random-values" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/zero-address/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "zero-address" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /detectors/unsafe-map-get/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-map-get" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | charset = utf-8 9 | 10 | [*.{js,jsx,ts,tsx}] 11 | indent_size = 2 12 | 13 | [*.{rs,py}] 14 | indent_size = 4 15 | 16 | [*.go] 17 | indent_style = tab 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | 22 | [Makefile] 23 | indent_style = tab 24 | -------------------------------------------------------------------------------- /detectors/dos-unexpected-revert-with-vector/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unexpected-revert-with-vector" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | 14 | [package.metadata.rust-analyzer] 15 | rustc_private = true 16 | -------------------------------------------------------------------------------- /detectors/set-contract-storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /detectors/iterators-over-indexing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "iterators-over-indexing" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-3/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-remediated-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-3/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-vulnerable-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-4/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-remediated-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-4/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-vulnerable-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-5/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-remediated-5" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/unsafe-expect-5/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-expect-vulnerable-5" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-3/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-remediated-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-3/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-vulnerable-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-4/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-remediated-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-4/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-vulnerable-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-5/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-remediated-5" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-5/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-vulnerable-5" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-6/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-remediated-6" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-6/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unsafe-unwrap-vulnerable-6" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /detectors/integer-overflow-or-underflow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /detectors/unprotected-mapping-operation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unprotected-mapping-operation" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /test-cases/soroban-version/soroban-version-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "soroban-version-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/soroban-version/soroban-version-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "soroban-version-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /detectors/soroban-version/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "soroban-version" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | semver = "1.0.4" 13 | serde_json = "1.0" 14 | ureq = { version = "2.7.1", features = ["json"] } 15 | 16 | [package.metadata.rust-analyzer] 17 | rustc_private = true 18 | -------------------------------------------------------------------------------- /test-cases/assert-violation/assert-violation-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "assert-violation-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/assert-violation/assert-violation-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "assert-violation-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unsafe-map-get/unsafe-map-get-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unsafe-map-get-remediated-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/unsafe-map-get/unsafe-map-get-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unsafe-map-get-vulnerable-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-unsafe-block-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-unsafe-block-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unused-return-enum-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unused-return-enum-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unused-return-enum-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unused-return-enum-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-3/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-remediated-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-3/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-vulnerable-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-4/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-remediated-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-4/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "set-contract-storage-vulnerable-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /detectors/vec-could-be-mapping/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "vec-could-be-mapping" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | itertools = { workspace = true } 14 | utils = { workspace = true } 15 | 16 | [package.metadata.rust-analyzer] 17 | rustc_private = true 18 | -------------------------------------------------------------------------------- /test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-core-mem-forget-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "avoid-core-mem-forget-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "divide-before-multiply-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "divide-before-multiply-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "divide-before-multiply-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "divide-before-multiply-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-3/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "divide-before-multiply-remediated-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-3/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "divide-before-multiply-vulnerable-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /detectors/unprotected-update-current-contract-wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unprotected-update-current-contract-wasm" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | clippy_utils = { workspace = true } 11 | dylint_linting = { workspace = true } 12 | if_chain = { workspace = true } 13 | utils = { workspace = true } 14 | 15 | [package.metadata.rust-analyzer] 16 | rustc_private = true 17 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unbounded-operation-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unbounded-operation-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unbounded-operation-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unbounded-operation-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-3/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unbounded-operation-remediated-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-3/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unbounded-operation-vulnerable-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/incorrect-exponentiation/incorrect-exponentiation-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "incorrect-exponentiation-remediated-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/incorrect-exponentiation/incorrect-exponentiation-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "incorrect-exponentiation-vulnerable-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/iterators-over-indexing/iterators-over-indexing-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "iterators-over-indexing-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/iterators-over-indexing/iterators-over-indexing-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "iterators-over-indexing-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unrestricted-transfer-from-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /docs/blog/2019-05-28-first-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: first-blog-post 3 | title: First Blog Post 4 | authors: 5 | name: Gao Wei 6 | title: Docusaurus Core Team 7 | url: https://github.com/wgao19 8 | image_url: https://github.com/wgao19.png 9 | tags: [hola, docusaurus] 10 | --- 11 | 12 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 13 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-3/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-remediated-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-4/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-remediated-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-5/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-remediated-5" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-5/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-vulnerable-5" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "unrestricted-transfer-from-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | -------------------------------------------------------------------------------- /test-cases/insufficiently-random-values/insufficiently-random-values-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "insufficiently-random-values-remediated-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/insufficiently-random-values/insufficiently-random-values-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "insufficiently-random-values-vulnerable-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-3/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-vulnerable-3" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-4/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "integer-overflow-or-underflow-vulnerable-4" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | -------------------------------------------------------------------------------- /test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-mapping-operation-remediated-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-mapping-operation-vulnerable-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-mapping-operation-remediated-2" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-mapping-operation-vulnerable-2" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unexpected-revert-with-vector-remediated-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unexpected-revert-with-vector-vulnerable-1" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unexpected-revert-with-vector-remediated-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "dos-unexpected-revert-with-vector-vulnerable-2" 4 | version = "0.1.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { workspace = true } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { workspace = true, features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | -------------------------------------------------------------------------------- /docs/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 996px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | -------------------------------------------------------------------------------- /detectors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", ".vscode", "target"] 3 | members = ["*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "51a1cf0" } 8 | common = { path = "common" } 9 | dylint_linting = { package = "scout-audit-dylint-linting", git = "https://github.com/CoinFabrik/scout-audit/", rev = "6d6819a" } 10 | if_chain = "=1.0.2" 11 | itertools = { version = "=0.13" } 12 | utils = { path = "../utils" } 13 | -------------------------------------------------------------------------------- /test-cases/unsafe-expect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["unsafe-expect-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/unsafe-map-get/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["unsafe-map-get-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["unsafe-unwrap-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/assert-violation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["assert-violation-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/avoid-panic-error/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["avoid-panic-error-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/soroban-version/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["soroban-version-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-update-current-contract-wasm-remediated-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-update-current-contract-wasm-vulnerable-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { workspace = true } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { workspace = true, features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | -------------------------------------------------------------------------------- /test-cases/avoid-unsafe-block/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["avoid-unsafe-block-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["unused-return-enum-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/avoid-core-mem-forget/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["avoid-core-mem-forget-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["divide-before-multiply-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["set-contract-storage-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["dos-unbounded-operation-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/incorrect-exponentiation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["incorrect-exponentiation-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "20.3.2" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/iterators-over-indexing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["iterators-over-indexing-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /docs/blog/authors.yml: -------------------------------------------------------------------------------- 1 | endi: 2 | name: Endilie Yacop Sucipto 3 | title: Maintainer of Docusaurus 4 | url: https://github.com/endiliey 5 | image_url: https://github.com/endiliey.png 6 | 7 | yangshun: 8 | name: Yangshun Tay 9 | title: Front End Engineer @ Facebook 10 | url: https://github.com/yangshun 11 | image_url: https://github.com/yangshun.png 12 | 13 | slorber: 14 | name: Sébastien Lorber 15 | title: Docusaurus maintainer 16 | url: https://sebastienlorber.com 17 | image_url: https://github.com/slorber.png 18 | -------------------------------------------------------------------------------- /test-cases/insufficiently-random-values/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["insufficiently-random-values-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["integer-overflow-or-underflow-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=21.3.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/unprotected-mapping-operation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["unprotected-mapping-operation-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /test-cases/unrestricted-transfer-from/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["unrestricted-transfer-from-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | 23 | -------------------------------------------------------------------------------- /test-cases/dos-unexpected-revert-with-vector/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["dos-unexpected-revert-with-vector-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | 23 | -------------------------------------------------------------------------------- /docs/blog/2021-08-01-mdx-blog-post.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: mdx-blog-post 3 | title: MDX Blog Post 4 | authors: [slorber] 5 | tags: [docusaurus] 6 | --- 7 | 8 | Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). 9 | 10 | :::tip 11 | 12 | Use the power of React to create interactive blog posts. 13 | 14 | ```js 15 | 16 | ``` 17 | 18 | 19 | 20 | ::: 21 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | exclude = [".cargo", "target"] 3 | members = ["unprotected-update-current-contract-wasm-*/*"] 4 | resolver = "2" 5 | 6 | [workspace.dependencies] 7 | soroban-sdk = { version = "=20.0.0" } 8 | 9 | [profile.release] 10 | codegen-units = 1 11 | debug = 0 12 | debug-assertions = false 13 | lto = true 14 | opt-level = "z" 15 | overflow-checks = true 16 | panic = "abort" 17 | strip = "symbols" 18 | 19 | [profile.release-with-logs] 20 | debug-assertions = true 21 | inherits = "release" 22 | -------------------------------------------------------------------------------- /docs/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | docsSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | }; 20 | 21 | module.exports = sidebars; 22 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DivideBeforeMultiply; 6 | 7 | #[contractimpl] 8 | impl DivideBeforeMultiply { 9 | pub fn split_profit(percentage: u64, total_profit: u64) -> u64 { 10 | (percentage * 100) / total_profit 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use crate::DivideBeforeMultiply; 17 | 18 | #[test] 19 | fn split_profit_works() { 20 | let result = DivideBeforeMultiply::split_profit(33, 100); 21 | assert_eq!(result, 33); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DivideBeforeMultiply; 6 | 7 | #[contractimpl] 8 | impl DivideBeforeMultiply { 9 | pub fn split_profit(percentage: u64, total_profit: u64) -> u64 { 10 | (percentage / 100) * total_profit 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use crate::DivideBeforeMultiply; 17 | 18 | #[test] 19 | fn split_profit_works() { 20 | let result = DivideBeforeMultiply::split_profit(33, 100); 21 | assert_eq!(result, 0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/test-case/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "incrementor" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = { version = "=20.0.0" } 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | [profile.release] 19 | opt-level = "z" 20 | overflow-checks = true 21 | debug = 0 22 | strip = "symbols" 23 | debug-assertions = false 24 | panic = "abort" 25 | codegen-units = 1 26 | lto = true 27 | 28 | [profile.release-with-logs] 29 | inherits = "release" 30 | debug-assertions = true -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-3/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DivideBeforeMultiply; 6 | 7 | #[contractimpl] 8 | impl DivideBeforeMultiply { 9 | pub fn hybrid_split_profit(percentage: u64, total_profit: u64) -> Option { 10 | (percentage * total_profit).checked_div(100) 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use crate::DivideBeforeMultiply; 17 | 18 | #[test] 19 | fn hybrid_split_profit_works() { 20 | let result = DivideBeforeMultiply::hybrid_split_profit(33, 100); 21 | assert_eq!(result.unwrap(), 33); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-3/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DivideBeforeMultiply; 6 | 7 | #[contractimpl] 8 | impl DivideBeforeMultiply { 9 | pub fn hybrid_split_profit(percentage: u64, total_profit: u64) -> Option { 10 | Some(percentage.checked_div(100)? * total_profit) 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use crate::DivideBeforeMultiply; 17 | 18 | #[test] 19 | fn hybrid_split_profit_works() { 20 | let result = DivideBeforeMultiply::hybrid_split_profit(33, 100); 21 | assert_eq!(result.unwrap(), 0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test-cases/zero-address/zero-address-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zero-address-remediated-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = "20.0.0-rc2" 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | [profile.release] 19 | opt-level = "z" 20 | overflow-checks = true 21 | debug = 0 22 | strip = "symbols" 23 | debug-assertions = false 24 | panic = "abort" 25 | codegen-units = 1 26 | lto = true 27 | 28 | [profile.release-with-logs] 29 | inherits = "release" 30 | debug-assertions = true -------------------------------------------------------------------------------- /test-cases/zero-address/zero-address-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zero-address-vulnerable-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = "20.0.0-rc2" 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | [profile.release] 19 | opt-level = "z" 20 | overflow-checks = true 21 | debug = 0 22 | strip = "symbols" 23 | debug-assertions = false 24 | panic = "abort" 25 | codegen-units = 1 26 | lto = true 27 | 28 | [profile.release-with-logs] 29 | inherits = "release" 30 | debug-assertions = true -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-2/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DivideBeforeMultiply; 6 | 7 | #[contractimpl] 8 | impl DivideBeforeMultiply { 9 | pub fn checked_split_profit(percentage: u64, total_profit: u64) -> Option { 10 | percentage.checked_mul(100)?.checked_div(total_profit) 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use crate::DivideBeforeMultiply; 17 | 18 | #[test] 19 | fn checked_split_profit_works() { 20 | let result = DivideBeforeMultiply::checked_split_profit(33, 100); 21 | assert_eq!(result.unwrap(), 33); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test-cases/divide-before-multiply/divide-before-multiply-2/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DivideBeforeMultiply; 6 | 7 | #[contractimpl] 8 | impl DivideBeforeMultiply { 9 | pub fn checked_split_profit(percentage: u64, total_profit: u64) -> Option { 10 | percentage.checked_div(100)?.checked_mul(total_profit) 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use crate::DivideBeforeMultiply; 17 | 18 | #[test] 19 | fn checked_split_profit_works() { 20 | let result = DivideBeforeMultiply::checked_split_profit(33, 100); 21 | assert_eq!(result.unwrap(), 0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test-cases/vec-could-be-mapping/vec-could-be-mapping-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vec-could-be-mapping-remediated-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = "20.0.0-rc2" 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | [profile.release] 19 | opt-level = "z" 20 | overflow-checks = true 21 | debug = 0 22 | strip = "symbols" 23 | debug-assertions = false 24 | panic = "abort" 25 | codegen-units = 1 26 | lto = true 27 | 28 | [profile.release-with-logs] 29 | inherits = "release" 30 | debug-assertions = true -------------------------------------------------------------------------------- /test-cases/vec-could-be-mapping/vec-could-be-mapping-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vec-could-be-mapping-vulnerable-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | soroban-sdk = "20.0.0-rc2" 11 | 12 | [dev_dependencies] 13 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 14 | 15 | [features] 16 | testutils = ["soroban-sdk/testutils"] 17 | 18 | [profile.release] 19 | opt-level = "z" 20 | overflow-checks = true 21 | debug = 0 22 | strip = "symbols" 23 | debug-assertions = false 24 | panic = "abort" 25 | codegen-units = 1 26 | lto = true 27 | 28 | [profile.release-with-logs] 29 | inherits = "release" 30 | debug-assertions = true -------------------------------------------------------------------------------- /test-cases/overflow-check/overflow-check-1/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "overflow-check-remediated-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { version = "=20.0.0" } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | 19 | [profile.release] 20 | codegen-units = 1 21 | debug = 0 22 | debug-assertions = false 23 | lto = true 24 | opt-level = "z" 25 | overflow-checks = true 26 | panic = "abort" 27 | strip = "symbols" 28 | 29 | [profile.release-with-logs] 30 | debug-assertions = true 31 | inherits = "release" 32 | -------------------------------------------------------------------------------- /test-cases/overflow-check/overflow-check-1/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "overflow-check-vulnerable-1" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = { version = "=20.0.0" } 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | 19 | [profile.release] 20 | codegen-units = 1 21 | debug = 0 22 | debug-assertions = false 23 | lto = true 24 | opt-level = "z" 25 | overflow-checks = false 26 | panic = "abort" 27 | strip = "symbols" 28 | 29 | [profile.release-with-logs] 30 | debug-assertions = true 31 | inherits = "release" 32 | -------------------------------------------------------------------------------- /docs/docs/detectors/7-avoid-core-mem-forget.md: -------------------------------------------------------------------------------- 1 | # Avoid core mem forget usage 2 | 3 | ### What it does 4 | 5 | Checks for `core::mem::forget` usage. 6 | 7 | ### Why is this bad? 8 | 9 | This is a bad practice because it can lead to memory leaks, resource leaks and logic errors. 10 | 11 | ### Example 12 | 13 | ```rust 14 | pub fn forget_something(n: WithoutCopy) -> u64 { 15 | core::mem::forget(n); 16 | 0 17 | } 18 | ``` 19 | 20 | Use instead: 21 | 22 | ```rust 23 | pub fn forget_something(n: WithoutCopy) -> u64 { 24 | let _ = n; 25 | 0 26 | } 27 | ``` 28 | 29 | ### Implementation 30 | 31 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/avoid-core-mem-forget). -------------------------------------------------------------------------------- /docs/docs/detectors/12-soroban-version.md: -------------------------------------------------------------------------------- 1 | # Soroban version 2 | 3 | ### What it does 4 | 5 | Warns you if you are using an old version of Soroban in the `Cargo.toml`. 6 | 7 | ### Why is this bad? 8 | 9 | Using an old version of Soroban can be dangerous, as it may have bugs or security issues. 10 | 11 | ### Example 12 | 13 | ```toml 14 | [dependencies] 15 | soroban-sdk = { version = "=20.0.0" } 16 | 17 | [dev_dependencies] 18 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 19 | ``` 20 | 21 | Instead, use the latest available version in the `Cargo.toml`. 22 | 23 | ### Implementation 24 | 25 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/soroban-version). 26 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, contracttype, Address, BytesN, Env}; 4 | 5 | #[contracttype] 6 | #[derive(Clone)] 7 | enum DataKey { 8 | Admin, 9 | } 10 | 11 | #[contract] 12 | pub struct UpgradeableContract; 13 | 14 | #[contractimpl] 15 | impl UpgradeableContract { 16 | pub fn init(e: Env, admin: Address) { 17 | e.storage().instance().set(&DataKey::Admin, &admin); 18 | } 19 | 20 | pub fn version() -> u32 { 21 | 1 22 | } 23 | 24 | pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { 25 | e.deployer().update_current_contract_wasm(new_wasm_hash); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/remediated-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-update-current-contract-wasm-remediated-2" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = "=20.0.0" 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | 19 | [profile.release] 20 | codegen-units = 1 21 | debug = 0 22 | debug-assertions = false 23 | lto = true 24 | opt-level = "z" 25 | overflow-checks = true 26 | panic = "abort" 27 | strip = "symbols" 28 | 29 | [profile.release-with-logs] 30 | debug-assertions = true 31 | inherits = "release" 32 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/vulnerable-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | edition = "2021" 4 | name = "unprotected-update-current-contract-wasm-vulnerable-2" 5 | version = "0.1.0" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | soroban-sdk = "=20.0.0" 12 | 13 | [dev_dependencies] 14 | soroban-sdk = { version = "=20.0.0", features = ["testutils"] } 15 | 16 | [features] 17 | testutils = ["soroban-sdk/testutils"] 18 | 19 | [profile.release] 20 | codegen-units = 1 21 | debug = 0 22 | debug-assertions = false 23 | lto = true 24 | opt-level = "z" 25 | overflow-checks = true 26 | panic = "abort" 27 | strip = "symbols" 28 | 29 | [profile.release-with-logs] 30 | debug-assertions = true 31 | inherits = "release" 32 | -------------------------------------------------------------------------------- /docs/docs/detectors/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Detectors 6 | 7 | In this section we introduce our set of detectors powered by [Dylint](https://github.com/trailofbits/dylint) - a Rust linting tool. 8 | 9 | Similar to [Clippy](https://github.com/rust-lang/rust-clippy), Dylint can run lints to help identify potential issues in code. However, unlike Clippy, Dylint can run lints from user-specified dynamic libraries instead of just a statically predetermined set. This unique feature of Dylint makes it easier for developers to extend and customize their own personal lint collections, leading to reduced compile and run cycles. 10 | 11 | Check our [Proof of Concept Study](https://github.com/CoinFabrik/web3-grant/tree/main/detectors) for a more detailed analysis of different detection techniques and tools. -------------------------------------------------------------------------------- /test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, contracttype}; 3 | 4 | #[contract] 5 | pub struct AvoidCoreMemForget; 6 | 7 | #[contracttype] 8 | #[derive(Eq, PartialEq)] 9 | pub struct WithoutCopy { 10 | pub a: u64, 11 | pub b: u64, 12 | } 13 | 14 | #[contractimpl] 15 | impl AvoidCoreMemForget { 16 | pub fn forget_something(n: WithoutCopy) -> u64 { 17 | let _ = n; 18 | 0 19 | } 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use crate::*; 25 | 26 | #[test] 27 | fn test_forget_something() { 28 | let test_value: WithoutCopy = WithoutCopy { a: 80, b: 60 }; 29 | 30 | let result = AvoidCoreMemForget::forget_something(test_value); 31 | 32 | assert_eq!(result, 0); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/docs/detectors/15-assert-violation.md: -------------------------------------------------------------------------------- 1 | # Assert violation 2 | 3 | ### What it does​ 4 | 5 | Checks for `assert!` macro usage. 6 | 7 | ### Why is this bad?​ 8 | 9 | The `assert!` macro can cause the contract to panic. 10 | 11 | ### Example​ 12 | 13 | ```rust 14 | pub fn assert_if_greater_than_10(_env: Env, value: u128) -> bool { 15 | assert!(value <= 10, "value should be less than 10"); 16 | true 17 | } 18 | 19 | ``` 20 | Use instead: 21 | 22 | ```rust 23 | pub fn assert_if_greater_than_10(_env: Env, value: u128) -> Result { 24 | if value <= 10 { 25 | Ok(true) 26 | } else { 27 | Err(AVError::GreaterThan10) 28 | } 29 | } 30 | ``` 31 | ### Implementation 32 | 33 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/assert-violation). 34 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, contracttype, Address, BytesN, Env}; 4 | 5 | #[contracttype] 6 | #[derive(Clone)] 7 | enum DataKey { 8 | Admin, 9 | } 10 | 11 | #[contract] 12 | pub struct UpgradeableContract; 13 | 14 | #[contractimpl] 15 | impl UpgradeableContract { 16 | pub fn init(e: Env, admin: Address) { 17 | e.storage().instance().set(&DataKey::Admin, &admin); 18 | } 19 | 20 | pub fn version() -> u32 { 21 | 1 22 | } 23 | 24 | pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { 25 | let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); 26 | admin.require_auth(); 27 | 28 | e.deployer().update_current_contract_wasm(new_wasm_hash); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/blog/2021-08-26-welcome/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: welcome 3 | title: Welcome 4 | authors: [slorber, yangshun] 5 | tags: [facebook, hello, docusaurus] 6 | --- 7 | 8 | [Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). 9 | 10 | Simply add Markdown files (or folders) to the `blog` directory. 11 | 12 | Regular blog authors can be added to `authors.yml`. 13 | 14 | The blog post date can be extracted from filenames, such as: 15 | 16 | - `2019-05-30-welcome.md` 17 | - `2019-05-30-welcome/index.md` 18 | 19 | A blog post folder can be convenient to co-locate blog post images: 20 | 21 | ![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) 22 | 23 | The blog supports tags as well! 24 | 25 | **And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ci: validate fmt lint test 2 | ci-no-test: validate fmt lint 3 | 4 | validate: 5 | @echo "\033[0;32m\n==> Validating the project structure and test cases... \033[0m" 6 | @python3 scripts/validate-detectors.py 7 | 8 | fmt: 9 | @echo "\033[0;32m\n---> Formatting test cases and detectors... \033[0m" 10 | @python3 scripts/run-fmt.py --dir test-cases detectors 11 | 12 | lint: 13 | @echo "\033[0;32m\n--> Linting test cases and detectors... \033[0m" 14 | @python3 scripts/run-clippy.py --dir test-cases detectors 15 | 16 | test: 17 | @echo "\033[0;32m\n--> Running tests for test cases... \033[0m" 18 | ifdef detector 19 | @detector_name=$(detector); \ 20 | python3 scripts/run-tests.py --detector=$$detector_name; 21 | else 22 | @for dir in test-cases/*; do \ 23 | if [ -d "$$dir" ]; then \ 24 | detector_name=$$(basename "$$dir"); \ 25 | python3 scripts/run-tests.py --detector=$$detector_name; \ 26 | fi; \ 27 | done 28 | endif 29 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, contracttype, Address, BytesN, Env}; 4 | 5 | #[contracttype] 6 | #[derive(Clone)] 7 | enum DataKey { 8 | Admin, 9 | } 10 | 11 | #[contract] 12 | pub struct UpgradeableContract; 13 | 14 | #[contractimpl] 15 | impl UpgradeableContract { 16 | pub fn init(e: Env, admin: Address) { 17 | e.storage().instance().set(&DataKey::Admin, &admin); 18 | } 19 | 20 | pub fn version() -> u32 { 21 | 1 22 | } 23 | 24 | pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { 25 | utils::upgrade(&e, new_wasm_hash); 26 | } 27 | } 28 | 29 | mod utils { 30 | use soroban_sdk::{BytesN, Env}; 31 | 32 | pub fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { 33 | env.deployer().update_current_contract_wasm(new_wasm_hash); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/docs/detectors/2-unsafe-unwrap.md: -------------------------------------------------------------------------------- 1 | # Unsafe unwrap 2 | 3 | ### What it does 4 | 5 | Checks for usage of `.unwrap()` 6 | 7 | ### Why is this bad? 8 | 9 | `.unwrap()` might panic if the result value is an error or `None`. 10 | 11 | ### Example 12 | 13 | ```rust 14 | // example code where a warning is issued 15 | fn main() { 16 | let result = result_fn().unwrap("error"); 17 | } 18 | fn result_fn() -> Result { 19 | Err(Error::new(ErrorKind::Other, "error")) 20 | } 21 | ``` 22 | 23 | Use instead: 24 | 25 | ```rust 26 | // example code that does not raise a warning 27 | fn main() { 28 | let result = if let Ok(result) = result_fn() { 29 | result 30 | } 31 | } 32 | fn result_fn() -> Result { 33 | Err(Error::new(ErrorKind::Other, "error")) 34 | } 35 | ``` 36 | 37 | ### Implementation 38 | 39 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/unsafe-unwrap). 40 | -------------------------------------------------------------------------------- /docs/docs/detectors/3-unsafe-expect.md: -------------------------------------------------------------------------------- 1 | # Unsafe expect 2 | 3 | ### What it does 4 | 5 | Checks for usage of `.expect()` 6 | 7 | ### Why is this bad? 8 | 9 | `.expect()` might panic if the result value is an error or `None`. 10 | 11 | ### Example 12 | 13 | ```rust 14 | // example code where a warning is issued 15 | fn main() { 16 | let result = result_fn().expect("error"); 17 | } 18 | fn result_fn() -> Result { 19 | Err(Error::new(ErrorKind::Other, "error")) 20 | } 21 | ``` 22 | 23 | Use instead: 24 | 25 | ```rust 26 | // example code that does not raise a warning 27 | fn main() { 28 | let result = if let Ok(result) = result_fn() { 29 | result 30 | } 31 | } 32 | fn result_fn() -> Result { 33 | Err(Error::new(ErrorKind::Other, "error")) 34 | } 35 | ``` 36 | 37 | ### Implementation 38 | 39 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/unsafe-expect). 40 | -------------------------------------------------------------------------------- /test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, contracttype}; 3 | 4 | #[contract] 5 | pub struct AvoidCoreMemForget; 6 | 7 | #[contracttype] 8 | #[derive(Eq, PartialEq)] 9 | pub struct WithoutCopy { 10 | pub a: u64, 11 | pub b: u64, 12 | } 13 | 14 | impl Drop for WithoutCopy { 15 | fn drop(&mut self) { 16 | // Prevent clippy warning 17 | } 18 | } 19 | 20 | #[contractimpl] 21 | impl AvoidCoreMemForget { 22 | pub fn forget_something(n: WithoutCopy) -> u64 { 23 | core::mem::forget(n); 24 | 0 25 | } 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use crate::*; 31 | 32 | #[test] 33 | fn test_forget_something() { 34 | let test_value: WithoutCopy = WithoutCopy { a: 80, b: 60 }; 35 | 36 | let result = AvoidCoreMemForget::forget_something(test_value); 37 | 38 | assert_eq!(result, 0); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docs/docs/detectors/8-set-contract-storage.md: -------------------------------------------------------------------------------- 1 | # Set contract storage 2 | 3 | ### What it does 4 | 5 | Checks for calls to `env.storage()` without a prior call to `env.require_auth()`. 6 | 7 | ### Why is this bad? 8 | 9 | Functions using keys as variables without proper access control or input sanitation can allow users to perform changes in arbitrary memory locations. 10 | 11 | ### Known problems 12 | 13 | Only check the function call, so false positives could result. 14 | 15 | ### Example 16 | 17 | ```rust 18 | fn set_contract_storage(env: Env) { 19 | let _storage = env.storage().instance(); 20 | } 21 | ``` 22 | 23 | Use instead: 24 | 25 | ```rust 26 | fn set_contract_storage(env: Env, user: Address) { 27 | user.require_auth(); 28 | let _storage = env.storage().instance(); 29 | } 30 | ``` 31 | 32 | ### Implementation 33 | 34 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/set-contract-storage). 35 | -------------------------------------------------------------------------------- /docs/docs/architecture.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Architecture 6 | 7 |

8 | Scout Architectural Diagram 9 |

10 | 11 | 12 | Scout is built on Trail of Bits’ [Dylint](https://github.com/trailofbits/dylint), featuring a new set of lints. Dylint is a static analyzer that interfaces with the Rust compiler, providing access to the High-Level Intermediate Representation and the Mid-Level Intermediate Representation. These representations enable the accurate capture of many vulnerabilities. The lints are specifically designed to detect certain vulnerability classes. They are files integrated into the tool during compilation, and adding new lints, or detectors as we call them, is straightforward for any contributor. We have also contributed to the Dylint project, enhancing its capabilities to produce outputs in various formats, including PDF reports. 13 | 14 | -------------------------------------------------------------------------------- /docs/docs/vscode-extension.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 8 3 | --- 4 | 5 | # Scout VS Code Extension 6 | 7 | Add Scout to your development workspace with Scout's VS Code extension and run Scout automatically upon saving your file. 8 | 9 | ![Scout VS Code extension.](../static/img/vscode-extension.png) 10 | 11 | :warning: To ensure the extension runs properly, make sure that you open the directory containing your smart contract, rather than the entire project. For example, if your smart contracts are located in `myproject/contracts`, and you want to work on the `token` contract while using the Scout VS Code Extension, open `myproject/contracts/token`. 12 | 13 | :bulb: Tip: To see the errors highlighted in your code, we recommend installing the [Error Lens Extension](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens). 14 | 15 | :point_right: Download Scout VS Code from [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=CoinFabrik.scout-audit). 16 | 17 | -------------------------------------------------------------------------------- /docs/docs/detectors/21-incorrect-exponentiation.md: -------------------------------------------------------------------------------- 1 | # Incorrect Exponentiation 2 | 3 | ### What it does 4 | 5 | Warns about `^` being a `bit XOR` operation instead of an exponentiation. 6 | 7 | ### Why is this bad? 8 | 9 | It can introduce unexpected behaviour in the smart contract. 10 | 11 | #### More info 12 | 13 | - https://doc.rust-lang.org/std/ops/trait.BitXor.html#tymethod.bitxor 14 | 15 | ### Example 16 | 17 | ```rust 18 | pub fn init(e: Env){ 19 | e.storage() 20 | .instance() 21 | .set::(&DataKey::Data, &((255_u128 ^ 2) - 1)); 22 | } 23 | ``` 24 | Use instead: 25 | 26 | ```rust 27 | pub fn init(e: Env) { 28 | e.storage() 29 | .instance() 30 | .set::(&DataKey::Data, &(255_u128.pow(2) - 1)); 31 | } 32 | ``` 33 | 34 | ### Implementation 35 | 36 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/incorrect-exponentiation). 37 | -------------------------------------------------------------------------------- /docs/docs/detectors/1-divide-before-multiply.md: -------------------------------------------------------------------------------- 1 | # Divide before multiply 2 | 3 | ### What it does 4 | 5 | Checks the existence of a division before a multiplication. 6 | 7 | ### Why is this bad? 8 | 9 | Performing a division operation before multiplication can lead to a loss of precision. It might even result in an unintended zero value. 10 | 11 | ### Example 12 | 13 | ```rust 14 | // Example 1 - Vulnerable 15 | let x = 10; 16 | let y = 6; 17 | let z = x / y * 3; // z evaluates to 3 18 | 19 | // Example 2 - Vulnerable 20 | let a = 1; 21 | let b = 2; 22 | let c = a / b * 3; // c evaluates to 0 23 | ``` 24 | 25 | Use instead: 26 | 27 | ```rust 28 | // Example 1 - Remediated 29 | let x = 10; 30 | let y = 6; 31 | let z = x * 3 / y; // z evaluates to 5 32 | 33 | // Example 2 - Remediated 34 | let a = 1; 35 | let b = 2; 36 | let c = a * 3 / b; // c evaluates to 1 37 | ``` 38 | 39 | ### Implementation 40 | 41 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/divide-before-multiply). 42 | 43 | 44 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DosUnboundedOperation; 6 | 7 | const FIXED_COUNT: u64 = 1000; 8 | 9 | #[contractimpl] 10 | impl DosUnboundedOperation { 11 | pub fn restricted_loop_with_const() -> u64 { 12 | let mut sum = 0; 13 | for i in 0..FIXED_COUNT { 14 | sum += i; 15 | } 16 | sum 17 | } 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use soroban_sdk::Env; 23 | 24 | use crate::{DosUnboundedOperation, DosUnboundedOperationClient}; 25 | 26 | #[test] 27 | fn test_for_loop() { 28 | // Given 29 | let env = Env::default(); 30 | let contract_id = env.register_contract(None, DosUnboundedOperation); 31 | let client = DosUnboundedOperationClient::new(&env, &contract_id); 32 | 33 | // When 34 | let count = client.restricted_loop_with_const(); 35 | 36 | // Then 37 | assert_eq!(count, 499500); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-3/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DosUnboundedOperation; 6 | 7 | #[contractimpl] 8 | impl DosUnboundedOperation { 9 | pub fn safe_loop_with_array() -> u64 { 10 | let mut sum = 0; 11 | let known_array = [0; 8]; 12 | for i in 0..known_array.len() { 13 | sum += i; 14 | } 15 | sum as u64 16 | } 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | 22 | use soroban_sdk::Env; 23 | 24 | use crate::{DosUnboundedOperation, DosUnboundedOperationClient}; 25 | 26 | #[test] 27 | fn test_for_loop() { 28 | // Given 29 | let env = Env::default(); 30 | let contract_id = env.register_contract(None, DosUnboundedOperation); 31 | let client = DosUnboundedOperationClient::new(&env, &contract_id); 32 | 33 | // When 34 | let count = client.safe_loop_with_array(); 35 | 36 | // Then 37 | assert_eq!(count, 28); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, contracttype, Address, BytesN, Env}; 4 | 5 | #[contracttype] 6 | #[derive(Clone)] 7 | enum DataKey { 8 | Admin, 9 | } 10 | 11 | #[contract] 12 | pub struct UpgradeableContract; 13 | 14 | #[contractimpl] 15 | impl UpgradeableContract { 16 | pub fn init(e: Env, admin: Address) { 17 | e.storage().instance().set(&DataKey::Admin, &admin); 18 | } 19 | 20 | pub fn version() -> u32 { 21 | 1 22 | } 23 | 24 | pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { 25 | let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); 26 | admin.require_auth(); 27 | 28 | utils::upgrade(&e, new_wasm_hash); 29 | } 30 | } 31 | 32 | mod utils { 33 | use soroban_sdk::{BytesN, Env}; 34 | 35 | pub fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { 36 | env.deployer().update_current_contract_wasm(new_wasm_hash); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | 4 | #[contract] 5 | pub struct DosUnboundedOperation; 6 | 7 | #[contractimpl] 8 | impl DosUnboundedOperation { 9 | pub fn unrestricted_loop(for_loop_count: u64) -> u64 { 10 | let mut count = 0; 11 | for i in 0..for_loop_count { 12 | count += i; 13 | } 14 | count 15 | } 16 | } 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | use soroban_sdk::Env; 21 | 22 | use crate::{DosUnboundedOperation, DosUnboundedOperationClient}; 23 | 24 | #[test] 25 | fn test_for_loop() { 26 | // Given 27 | let env = Env::default(); 28 | let contract_id = env.register_contract(None, DosUnboundedOperation); 29 | let client = DosUnboundedOperationClient::new(&env, &contract_id); 30 | 31 | // When 32 | let for_loop_count = 1000; 33 | let count = client.unrestricted_loop(&for_loop_count); 34 | 35 | // Then 36 | assert_eq!(count, 499500); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | #[contract] 4 | pub struct AvoidUnsafeBlock; 5 | #[contractimpl] 6 | impl AvoidUnsafeBlock { 7 | pub fn unsafe_function(n: u64) -> u64 { 8 | let mut i = n as f64; 9 | let mut y = i.to_bits(); 10 | y = 0x5fe6ec85e7de30da - (y >> 1); 11 | i = f64::from_bits(y); 12 | i *= 1.5 - 0.5 * n as f64 * i * i; 13 | i *= 1.5 - 0.5 * n as f64 * i * i; 14 | i.to_bits() 15 | } 16 | } 17 | #[cfg(test)] 18 | mod tests { 19 | use crate::AvoidUnsafeBlock; 20 | #[test] 21 | fn test_unsafe_block() { 22 | let test_value = 8; 23 | let result = AvoidUnsafeBlock::unsafe_function(test_value); 24 | let inverse = inverse_square_root_without_unsafe(test_value); 25 | 26 | assert_eq!((inverse - result) / inverse, 0); 27 | assert_eq!((inverse - result) / result, 0); 28 | } 29 | 30 | fn inverse_square_root_without_unsafe(n: u64) -> u64 { 31 | (1.0 / (n as f64).sqrt()).to_bits() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/project-tasks.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Project task 3 | about: Project task details 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description 11 | Detailed explanation of the task. This should include any specific requirements, goals, and desired outcomes. It should also include any necessary context or background information. 12 | 13 | ## Acceptance Criteria 14 | - Clear, actionable items that must be met for the task to be considered complete. 15 | - For example, "The user can successfully log in with their email and password." 16 | - Acceptance criteria should be testable and should align with the task's goals and requirements. 17 | 18 | ## Subtasks 19 | - [ ] Subtask 1: Brief description of the first subtask. 20 | - [ ] Subtask 2: Brief description of the second subtask. 21 | - [ ] Subtask 3: Brief description of the third subtask. 22 | 23 | *Note: use checklists ;) 24 | 25 | ## Estimate 26 | How long you expect this task to take, in days. This is just an estimate and can be adjusted as necessary. 27 | 28 | ## Sprint number 29 | The sprint in which this task is scheduled to be worked on. 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 CoinFabrik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-3/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, BytesN}; 3 | 4 | #[contract] 5 | pub struct DosUnboundedOperation; 6 | 7 | #[contractimpl] 8 | impl DosUnboundedOperation { 9 | pub fn unsafe_loop_with_array(unknown_array: BytesN<8>) -> u32 { 10 | let mut sum = 0; 11 | for i in 0..unknown_array.len() { 12 | sum += i; 13 | } 14 | sum 15 | } 16 | } 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | 21 | use soroban_sdk::{BytesN, Env}; 22 | 23 | use crate::{DosUnboundedOperation, DosUnboundedOperationClient}; 24 | 25 | #[test] 26 | fn test_for_loop() { 27 | // Given 28 | let env = Env::default(); 29 | let contract_id = env.register_contract(None, DosUnboundedOperation); 30 | let client = DosUnboundedOperationClient::new(&env, &contract_id); 31 | 32 | // When 33 | let unknown_array = BytesN::from_array(&env, &[0; 8]); 34 | let count = client.unsafe_loop_with_array(&unknown_array); 35 | 36 | // Then 37 | assert_eq!(count, 28); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test-cases/unsafe-map-get/unsafe-map-get-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, map, Env, IntoVal, Map, TryIntoVal, Val}; 4 | 5 | #[contract] 6 | pub struct UnsafeMapGet; 7 | 8 | #[contractimpl] 9 | impl UnsafeMapGet { 10 | pub fn get_from_map(env: Env) -> Option { 11 | let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env))]; 12 | let map: Val = map.into(); 13 | let map: Map = map.try_into_val(&env).unwrap(); 14 | map.get(1) 15 | } 16 | } 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | use soroban_sdk::Env; 21 | 22 | use crate::{UnsafeMapGet, UnsafeMapGetClient}; 23 | 24 | #[test] 25 | #[should_panic(expected = "ConversionError")] 26 | fn test_insert_balances() { 27 | // Given 28 | let env = Env::default(); 29 | let contract_id = env.register_contract(None, UnsafeMapGet); 30 | let client = UnsafeMapGetClient::new(&env, &contract_id); 31 | 32 | // When 33 | let _value = client.get_from_map(); 34 | 35 | // Then 36 | 37 | // Test should panic 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test-cases/vec-could-be-mapping/vec-could-be-mapping-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | #[cfg(any(test, feature = "testutils"))] 4 | extern crate std; 5 | 6 | use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, Env}; 7 | 8 | #[contracttype] 9 | #[derive(Clone)] 10 | enum DataKey { 11 | Data(Address), 12 | } 13 | 14 | #[contract] 15 | pub struct NonPayableTransferredValueContract; 16 | 17 | #[contracterror] 18 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 19 | #[repr(u32)] 20 | pub enum Error { 21 | Ununitialized = 1, 22 | NoData = 2, 23 | NotFound = 3, 24 | } 25 | 26 | #[contractimpl] 27 | impl NonPayableTransferredValueContract { 28 | pub fn add_data(e: Env, key: Address, value: i64) -> Result<(), Error> { 29 | e.storage().persistent().set(&DataKey::Data(key), &value); 30 | Ok(()) 31 | } 32 | 33 | pub fn get(e: Env, key: Address) -> Result { 34 | e.storage() 35 | .persistent() 36 | .get::(&DataKey::Data(key)) 37 | .ok_or(Error::NotFound) 38 | } 39 | } 40 | 41 | #[test] 42 | fn simple_test() {} 43 | -------------------------------------------------------------------------------- /docs/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #1DA0C2; 10 | --ifm-color-primary-dark: #1884a0; 11 | --ifm-color-primary-darker: #16758d; 12 | --ifm-color-primary-darkest: #116074; 13 | --ifm-color-primary-light: #22afd2; 14 | --ifm-color-primary-lighter: #26bbe1; 15 | --ifm-color-primary-lightest: #40d0f4; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #25c2a0; 23 | --ifm-color-primary-dark: #21af90; 24 | --ifm-color-primary-darker: #1fa588; 25 | --ifm-color-primary-darkest: #1a8870; 26 | --ifm-color-primary-light: #29d5b0; 27 | --ifm-color-primary-lighter: #32d8b4; 28 | --ifm-color-primary-lightest: #4fddbf; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | } 31 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-2/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, contracttype}; 3 | 4 | #[contract] 5 | pub struct DosUnboundedOperation; 6 | 7 | #[contracttype] 8 | pub struct KnownData { 9 | fixed_value: u64, 10 | } 11 | 12 | #[contractimpl] 13 | impl DosUnboundedOperation { 14 | pub fn safe_loop_with_struct() -> u64 { 15 | let mut sum = 0; 16 | let known_data = KnownData { fixed_value: 1000 }; 17 | for i in 0..known_data.fixed_value { 18 | sum += i; 19 | } 20 | sum 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | 27 | use soroban_sdk::Env; 28 | 29 | use crate::{DosUnboundedOperation, DosUnboundedOperationClient}; 30 | 31 | #[test] 32 | fn test_for_loop() { 33 | // Given 34 | let env = Env::default(); 35 | let contract_id = env.register_contract(None, DosUnboundedOperation); 36 | let client = DosUnboundedOperationClient::new(&env, &contract_id); 37 | 38 | // When 39 | let count = client.safe_loop_with_struct(); 40 | 41 | // Then 42 | assert_eq!(count, 499500); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/docs/detectors/11-dos-unbounded-operation.md: -------------------------------------------------------------------------------- 1 | # DoS unbounded operation 2 | 3 | ### What it does 4 | 5 | This detector checks that when using for or while loops, their conditions limit the execution to a constant number of iterations. 6 | 7 | ### Why is this bad? 8 | 9 | If the number of iterations is not limited to a specific range, it could potentially cause out of gas exceptions. 10 | 11 | ### Known problems 12 | 13 | False positives are to be expected when using variables that can only be set using controlled flows that limit the values within acceptable ranges. 14 | 15 | ### Example 16 | 17 | ```rust 18 | pub fn unrestricted_loop(for_loop_count: u64) -> u64 { 19 | let mut count = 0; 20 | for i in 0..for_loop_count { 21 | count += i; 22 | } 23 | count 24 | } 25 | ``` 26 | 27 | Use instead: 28 | 29 | ```rust 30 | const FIXED_COUNT: u64 = 1000; 31 | 32 | pub fn restricted_loop_with_const() -> u64 { 33 | let mut sum = 0; 34 | for i in 0..FIXED_COUNT { 35 | sum += i; 36 | } 37 | sum 38 | } 39 | ``` 40 | 41 | ### Implementation 42 | 43 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/dos-unbounded-operation). -------------------------------------------------------------------------------- /test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl}; 3 | #[contract] 4 | pub struct AvoidUnsafeBlock; 5 | #[contractimpl] 6 | impl AvoidUnsafeBlock { 7 | pub fn unsafe_function(n: u64) -> u64 { 8 | unsafe { 9 | let mut i = n as f64; 10 | let mut y = i.to_bits(); 11 | y = 0x5fe6ec85e7de30da - (y >> 1); 12 | i = f64::from_bits(y); 13 | i *= 1.5 - 0.5 * n as f64 * i * i; 14 | i *= 1.5 - 0.5 * n as f64 * i * i; 15 | 16 | let result_ptr: *mut f64 = &mut i; 17 | 18 | (*result_ptr).to_bits() 19 | } 20 | } 21 | } 22 | #[cfg(test)] 23 | mod tests { 24 | use crate::AvoidUnsafeBlock; 25 | #[test] 26 | fn test_unsafe_block() { 27 | let test_value = 8; 28 | let result = AvoidUnsafeBlock::unsafe_function(test_value); 29 | let inverse = inverse_square_root_without_unsafe(test_value); 30 | 31 | assert_eq!((inverse - result) / inverse, 0); 32 | assert_eq!((inverse - result) / result, 0); 33 | } 34 | 35 | fn inverse_square_root_without_unsafe(n: u64) -> u64 { 36 | (1.0 / (n as f64).sqrt()).to_bits() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test-cases/dos-unbounded-operation/dos-unbounded-operation-2/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, contracttype}; 3 | 4 | #[contract] 5 | pub struct DosUnboundedOperation; 6 | 7 | #[contracttype] 8 | pub struct KnownData { 9 | fixed_value: u64, 10 | } 11 | 12 | #[contractimpl] 13 | impl DosUnboundedOperation { 14 | pub fn unsafe_loop_with_struct(unknown_data: KnownData) -> u64 { 15 | let mut sum = 0; 16 | for i in 0..unknown_data.fixed_value { 17 | sum += i; 18 | } 19 | sum 20 | } 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | 26 | use soroban_sdk::Env; 27 | 28 | use crate::{DosUnboundedOperation, DosUnboundedOperationClient, KnownData}; 29 | 30 | #[test] 31 | fn test_for_loop() { 32 | // Given 33 | let env = Env::default(); 34 | let contract_id = env.register_contract(None, DosUnboundedOperation); 35 | let client = DosUnboundedOperationClient::new(&env, &contract_id); 36 | 37 | // When 38 | let unknown_data = KnownData { fixed_value: 1000 }; 39 | let count = client.unsafe_loop_with_struct(&unknown_data); 40 | 41 | // Then 42 | assert_eq!(count, 499500); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------------- 2 | # -------------------------------------- Rust ----------------------------------------- 3 | # ------------------------------------------------------------------------------------- 4 | 5 | # Generated by Cargo 6 | # will have compiled files and executables 7 | debug/ 8 | target/ 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # Ignore Cargo.lock of library files 17 | test-cases/**/Cargo.lock 18 | detectors/**/Cargo.lock 19 | scout-audit-internal/Cargo.lock 20 | 21 | #ignore test generated files 22 | test-cases/**/test_snapshots/** 23 | 24 | # ------------------------------------------------------------------------------------- 25 | # -------------------------------------- Misc ----------------------------------------- 26 | # ------------------------------------------------------------------------------------- 27 | 28 | # OSX 29 | .DS_Store 30 | 31 | # Logs 32 | logs 33 | *.log 34 | 35 | # Environment variables 36 | .env 37 | .env.* 38 | node_modules 39 | 40 | # Editors 41 | .vscode/ 42 | .idea/ 43 | !/.vscode/ 44 | 45 | **/__pycache__/ 46 | env/ 47 | -------------------------------------------------------------------------------- /templates/test-case/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, log, symbol_short, Env, Symbol}; 3 | 4 | const COUNTER: Symbol = symbol_short!("COUNTER"); 5 | 6 | #[contract] 7 | pub struct IncrementorContract; 8 | 9 | #[contractimpl] 10 | impl IncrementorContract { 11 | /// Increment an internal counter; return the new value. 12 | pub fn increment(env: Env) -> u32 { 13 | let mut count: u32 = env.storage().instance().get(&COUNTER).unwrap_or(0); 14 | 15 | count += 1; 16 | 17 | log!(&env, "count: {}", count); 18 | 19 | env.storage().instance().set(&COUNTER, &count); 20 | 21 | env.storage().instance().extend_ttl(100, 100); 22 | 23 | count 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod test{ 29 | use crate::{IncrementorContract, IncrementorContractClient}; 30 | use soroban_sdk::{ Env }; 31 | 32 | #[test] 33 | fn increment() { 34 | let env = Env::default(); 35 | let contract_id = env.register_contract(None, IncrementorContract); 36 | let client = IncrementorContractClient::new(&env, &contract_id); 37 | 38 | assert_eq!(client.increment(), 1); 39 | assert_eq!(client.increment(), 2); 40 | assert_eq!(client.increment(), 3); 41 | } 42 | } -------------------------------------------------------------------------------- /docs/src/pages/about.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Layout from '@theme/Layout'; 3 | import Link from '@docusaurus/Link'; 4 | 5 | function About() { 6 | return ( 7 | 8 |
9 |

About

10 |

11 | We - CoinFabrik - are a research and development company specialized in Web3, with a strong background in cybersecurity. Founded in 2014, we have worked on over 180 blockchain-related projects, EVM based and also for Solana, Algorand, Stellar, and Polkadot. Beyond development, we offer security audits through a dedicated in-house team of senior cybersecurity professionals, currently working on code in Substrate, Solidity, Clarity, Rust, and TEAL. 12 |
13 |
14 | Our team has an academic background in computer science and mathematics, with work experience focused on cybersecurity and software development, including academic publications, patents turned into products, and conference presentations. Furthermore, we have an ongoing collaboration on knowledge transfer and open-source projects with the University of Buenos Aires. 15 |

16 |
17 |
18 | ); 19 | } 20 | 21 | export default About; 22 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scout", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "2.4.1", 19 | "@docusaurus/preset-classic": "2.4.1", 20 | "@mdx-js/react": "^1.6.22", 21 | "clsx": "^1.2.1", 22 | "prism-react-renderer": "^1.3.5", 23 | "react": "^17.0.2", 24 | "react-dom": "^17.0.2" 25 | }, 26 | "devDependencies": { 27 | "@docusaurus/module-type-aliases": "2.4.1", 28 | "@docusaurus/types": "^2.4.1", 29 | "@tsconfig/docusaurus": "^1.0.5", 30 | "typescript": "^4.7.4" 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.5%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | }, 44 | "engines": { 45 | "node": ">=16.14" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/docs/detectors/20-zero-or-test-address.md: -------------------------------------------------------------------------------- 1 | # Zero or test address 2 | 3 | ### What it does 4 | Checks whether the zero address is being inputed to a function without validation. 5 | 6 | ### Why is this bad? 7 | Because the private key for the zero address is known, anyone could take ownership of the contract. 8 | 9 | ### Example 10 | 11 | ```rust 12 | pub fn set(e: Env, admin: Address, data: i32) -> Result<(), Error> { 13 | if !ZeroAddressContract::ensure_is_admin(&e, admin)? { 14 | return Err(Error::NotAdmin); 15 | } 16 | e.storage().persistent().set(&DataKey::Data, &data); 17 | Ok(()) 18 | } 19 | ``` 20 | 21 | 22 | Use instead: 23 | ```rust 24 | pub fn set(e: Env, admin: Address, data: i32) -> Result<(), Error> { 25 | if admin 26 | == Address::from_string(&String::from_bytes( 27 | &e, 28 | b"GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", 29 | )) 30 | { 31 | return Err(Error::InvalidNewAdmin); 32 | } 33 | if !ZeroAddressContract::ensure_is_admin(&e, admin)? { 34 | return Err(Error::NotAdmin); 35 | } 36 | e.storage().persistent().set(&DataKey::Data, &data); 37 | Ok(()) 38 | } 39 | ``` 40 | 41 | ### Implementation 42 | 43 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/zero-or-test-address). 44 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn unwrap_or_default(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | result.unwrap_or(0) 19 | } 20 | 21 | pub fn non_zero_or_error(n: u64) -> Result { 22 | if n == 0 { 23 | return Err(Error::CustomError); 24 | } 25 | Ok(n) 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use crate::UnsafeUnwrap; 32 | 33 | #[test] 34 | fn test_unwrap_zero() { 35 | // Given 36 | let test_value = 0; 37 | 38 | // When 39 | let result = UnsafeUnwrap::unwrap_or_default(test_value); 40 | 41 | // Then 42 | assert_eq!(result, test_value); 43 | } 44 | 45 | #[test] 46 | fn test_unwrap_non_zero() { 47 | // Given 48 | let test_value = 100; 49 | 50 | // When 51 | let result = UnsafeUnwrap::unwrap_or_default(test_value); 52 | 53 | // Then 54 | assert_eq!(result, test_value); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn unwrap(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | result.unwrap() 19 | } 20 | 21 | pub fn non_zero_or_error(n: u64) -> Result { 22 | if n == 0 { 23 | return Err(Error::CustomError); 24 | } 25 | Ok(n) 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use crate::UnsafeUnwrap; 32 | 33 | #[test] 34 | #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: CustomError")] 35 | fn test_unwrap_zero() { 36 | // Given 37 | let test_value = 0; 38 | 39 | // When 40 | let _result = UnsafeUnwrap::unwrap(test_value); 41 | 42 | // Then 43 | // The test should panic 44 | } 45 | 46 | #[test] 47 | fn test_unwrap_non_zero() { 48 | // Given 49 | let test_value = 100; 50 | 51 | // When 52 | let result = UnsafeUnwrap::unwrap(test_value); 53 | 54 | // Then 55 | assert_eq!(result, test_value); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-2/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn safe_unwrap(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | if result.is_err() { 19 | return 0; 20 | } 21 | result.unwrap() 22 | } 23 | 24 | pub fn non_zero_or_error(n: u64) -> Result { 25 | if n == 0 { 26 | return Err(Error::CustomError); 27 | } 28 | Ok(n) 29 | } 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use crate::UnsafeUnwrap; 35 | 36 | #[test] 37 | fn test_unwrap_zero() { 38 | // Given 39 | let test_value = 0; 40 | 41 | // When 42 | let result = UnsafeUnwrap::safe_unwrap(test_value); 43 | 44 | // Then 45 | assert_eq!(result, test_value); 46 | } 47 | 48 | #[test] 49 | fn test_unwrap_non_zero() { 50 | // Given 51 | let test_value = 100; 52 | 53 | // When 54 | let result = UnsafeUnwrap::safe_unwrap(test_value); 55 | 56 | // Then 57 | assert_eq!(result, test_value); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-2/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn unwrap(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | result.unwrap() 19 | } 20 | 21 | pub fn non_zero_or_error(n: u64) -> Result { 22 | if n == 0 { 23 | return Err(Error::CustomError); 24 | } 25 | Ok(n) 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use crate::UnsafeUnwrap; 32 | 33 | #[test] 34 | #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: CustomError")] 35 | fn test_unwrap_zero() { 36 | // Given 37 | let test_value = 0; 38 | 39 | // When 40 | let _result = UnsafeUnwrap::unwrap(test_value); 41 | 42 | // Then 43 | // The test should panic 44 | } 45 | 46 | #[test] 47 | fn test_unwrap_non_zero() { 48 | // Given 49 | let test_value = 100; 50 | 51 | // When 52 | let result = UnsafeUnwrap::unwrap(test_value); 53 | 54 | // Then 55 | assert_eq!(result, test_value); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-3/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn unwrap(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | result.unwrap() 19 | } 20 | 21 | pub fn non_zero_or_error(n: u64) -> Result { 22 | if n == 0 { 23 | return Err(Error::CustomError); 24 | } 25 | Ok(n) 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use crate::UnsafeUnwrap; 32 | 33 | #[test] 34 | #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: CustomError")] 35 | fn test_unwrap_zero() { 36 | // Given 37 | let test_value = 0; 38 | 39 | // When 40 | let _result = UnsafeUnwrap::unwrap(test_value); 41 | 42 | // Then 43 | // The test should panic 44 | } 45 | 46 | #[test] 47 | fn test_unwrap_non_zero() { 48 | // Given 49 | let test_value = 100; 50 | 51 | // When 52 | let result = UnsafeUnwrap::unwrap(test_value); 53 | 54 | // Then 55 | assert_eq!(result, test_value); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-5/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, symbol_short, Env, Symbol}; 4 | 5 | #[contract] 6 | pub struct IntegerOverflowUnderflow; 7 | 8 | #[contractimpl] 9 | impl IntegerOverflowUnderflow { 10 | const VALUE: Symbol = symbol_short!("VALUE"); 11 | 12 | pub fn initialize(env: Env, value: i32) { 13 | env.storage().temporary().set(&Self::VALUE, &value); 14 | } 15 | 16 | pub fn neg(env: Env) { 17 | let current: i32 = env.storage().temporary().get(&Self::VALUE).unwrap_or(0); 18 | let new_value = -current; 19 | env.storage().temporary().set(&Self::VALUE, &new_value); 20 | } 21 | 22 | pub fn get(env: Env) -> i32 { 23 | env.storage().temporary().get(&Self::VALUE).unwrap_or(0) 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod test { 29 | use super::*; 30 | use soroban_sdk::Env; 31 | 32 | #[test] 33 | #[should_panic(expected = "attempt to negate with overflow")] 34 | fn test_neg() { 35 | // Given 36 | let env = Env::default(); 37 | let contract_id = env.register_contract(None, IntegerOverflowUnderflow); 38 | let client = IntegerOverflowUnderflowClient::new(&env, &contract_id); 39 | 40 | // When 41 | client.initialize(&i32::MIN); 42 | client.neg(); 43 | 44 | // Then 45 | // Panic 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/docs/vulnerabilities/4-overflow-check.md: -------------------------------------------------------------------------------- 1 | # Overflow check 2 | 3 | ## Description 4 | 5 | - Vulnerability Category: `Arithmetic` 6 | - Vulnerability Severity: `Critical` 7 | - Detectors: [`overflow-check`](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/overflow-check) 8 | - Test Cases: [`overflow-check-1`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/overflow-check/overflow-check-1) 9 | 10 | Checks that `overflow-checks` is enabled in the `[profile.release]` section of the `Cargo.toml`. 11 | 12 | Integer overflow will trigger a panic in debug builds or will wrap in 13 | release mode. Division by zero will cause a panic in either mode. In some applications one 14 | wants explicitly checked, wrapping or saturating arithmetic. 15 | 16 | 17 | ## Exploit Scenario 18 | 19 | Consider the following `Cargo.toml`, in a `Soroban` contract: 20 | 21 | ```toml 22 | [profile.release] 23 | overflow-checks = false 24 | ``` 25 | 26 | Problems can arise if `overflow-checks` is disabled. 27 | 28 | The vulnerable code example can be found [`here`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/overflow-check/overflow-check-1/vulnerable-example). 29 | 30 | ## Remediation 31 | 32 | ```toml 33 | [profile.release] 34 | overflow-checks = true 35 | ``` 36 | 37 | The remediated code example can be found [`here`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/overflow-check/overflow-check-1/remediated-example). -------------------------------------------------------------------------------- /docs/docs/detectors/10-avoid-unsafe-block.md: -------------------------------------------------------------------------------- 1 | # Avoid unsafe block 2 | 3 | ### What it does 4 | 5 | Checks for usage of `unsafe` blocks. 6 | 7 | ### Why is this bad? 8 | 9 | `unsafe` blocks should not be used unless absolutely necessary. The use of unsafe blocks in Rust is discouraged because they bypass Rust's memory safety checks, potentially leading to issues like undefined behavior and security vulnerabilities. 10 | 11 | ### Example 12 | 13 | ```rust 14 | pub fn unsafe_function(n: u64) -> u64 { 15 | unsafe { 16 | let mut i = n as f64; 17 | let mut y = i.to_bits(); 18 | y = 0x5fe6ec85e7de30da - (y >> 1); 19 | i = f64::from_bits(y); 20 | i *= 1.5 - 0.5 * n as f64 * i * i; 21 | i *= 1.5 - 0.5 * n as f64 * i * i; 22 | 23 | let result_ptr: *mut f64 = &mut i; 24 | let result = *result_ptr; 25 | 26 | result.to_bits() 27 | } 28 | } 29 | ``` 30 | 31 | Use instead: 32 | 33 | ```rust 34 | pub fn unsafe_function(n: u64) -> u64 { 35 | let mut i = n as f64; 36 | let mut y = i.to_bits(); 37 | y = 0x5fe6ec85e7de30da - (y >> 1); 38 | i = f64::from_bits(y); 39 | i *= 1.5 - 0.5 * n as f64 * i * i; 40 | i *= 1.5 - 0.5 * n as f64 * i * i; 41 | result.to_bits() 42 | } 43 | ``` 44 | 45 | ### Implementation 46 | 47 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/avoid-unsafe-block). -------------------------------------------------------------------------------- /docs/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import Link from '@docusaurus/Link'; 4 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 5 | import Layout from '@theme/Layout'; 6 | import HomepageFeatures from '@site/src/components/HomepageFeatures'; 7 | 8 | import styles from './index.module.css'; 9 | 10 | function HomepageHeader() { 11 | const {siteConfig} = useDocusaurusContext(); 12 | return ( 13 |
14 |
15 |

{siteConfig.title}

16 |

{siteConfig.tagline}

17 |
18 | 21 | Get Started with Scout - 5min ⏱️ 22 | 23 |
24 |
25 |
26 | ); 27 | } 28 | 29 | export default function Home(): JSX.Element { 30 | const {siteConfig} = useDocusaurusContext(); 31 | return ( 32 | 34 | 35 |
36 | 37 |
38 |
39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, symbol_short, Env, Symbol}; 3 | 4 | #[contract] 5 | pub struct IntegerOverflowUnderflow; 6 | 7 | #[contractimpl] 8 | impl IntegerOverflowUnderflow { 9 | const VALUE: Symbol = symbol_short!("VALUE"); 10 | 11 | pub fn initialize(env: Env, value: u32) { 12 | env.storage().temporary().set(&Self::VALUE, &value); 13 | } 14 | 15 | pub fn add(env: Env, value: u32) { 16 | let current: u32 = env.storage().temporary().get(&Self::VALUE).unwrap_or(0); 17 | let new_value = current + value; 18 | env.storage().temporary().set(&Self::VALUE, &new_value); 19 | } 20 | 21 | pub fn get(env: Env) -> u32 { 22 | env.storage().temporary().get(&Self::VALUE).unwrap_or(0) 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod test { 28 | use super::*; 29 | use soroban_sdk::Env; 30 | 31 | #[test] 32 | #[should_panic(expected = "attempt to add with overflow")] 33 | fn test_add_overflow() { 34 | // Given 35 | let env = Env::default(); 36 | let contract_id = env.register_contract(None, IntegerOverflowUnderflow); 37 | let client = IntegerOverflowUnderflowClient::new(&env, &contract_id); 38 | 39 | // When 40 | client.initialize(&u32::MAX); 41 | client.add(&1); 42 | 43 | // Then 44 | // Panic 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-2/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, symbol_short, Env, Symbol}; 3 | 4 | #[contract] 5 | pub struct IntegerOverflowUnderflow; 6 | 7 | #[contractimpl] 8 | impl IntegerOverflowUnderflow { 9 | const VALUE: Symbol = symbol_short!("VALUE"); 10 | 11 | pub fn initialize(env: Env, value: u32) { 12 | env.storage().temporary().set(&Self::VALUE, &value); 13 | } 14 | 15 | pub fn sub(env: Env, value: u32) { 16 | let current: u32 = env.storage().temporary().get(&Self::VALUE).unwrap_or(0); 17 | let new_value = current - value; 18 | env.storage().temporary().set(&Self::VALUE, &new_value); 19 | } 20 | 21 | pub fn get(env: Env) -> u32 { 22 | env.storage().temporary().get(&Self::VALUE).unwrap_or(0) 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod test { 28 | use super::*; 29 | use soroban_sdk::Env; 30 | 31 | #[test] 32 | #[should_panic(expected = "attempt to subtract with overflow")] 33 | fn test_sub_underflow() { 34 | // Given 35 | let env = Env::default(); 36 | let contract_id = env.register_contract(None, IntegerOverflowUnderflow); 37 | let client = IntegerOverflowUnderflowClient::new(&env, &contract_id); 38 | 39 | // When 40 | client.initialize(&0); 41 | client.sub(&1); 42 | 43 | // Then 44 | // Panic 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-3/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, symbol_short, Env, Symbol}; 4 | 5 | #[contract] 6 | pub struct IntegerOverflowUnderflow; 7 | 8 | #[contractimpl] 9 | impl IntegerOverflowUnderflow { 10 | const VALUE: Symbol = symbol_short!("VALUE"); 11 | 12 | pub fn initialize(env: Env, value: u32) { 13 | env.storage().temporary().set(&Self::VALUE, &value); 14 | } 15 | 16 | pub fn mul(env: Env, value: u32) { 17 | let current: u32 = env.storage().temporary().get(&Self::VALUE).unwrap_or(0); 18 | let new_value = current * value; 19 | env.storage().temporary().set(&Self::VALUE, &new_value); 20 | } 21 | 22 | pub fn get(env: Env) -> u32 { 23 | env.storage().temporary().get(&Self::VALUE).unwrap_or(0) 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod test { 29 | use super::*; 30 | use soroban_sdk::Env; 31 | 32 | #[test] 33 | #[should_panic(expected = "attempt to multiply with overflow")] 34 | fn test_mul_overflow() { 35 | // Given 36 | let env = Env::default(); 37 | let contract_id = env.register_contract(None, IntegerOverflowUnderflow); 38 | let client = IntegerOverflowUnderflowClient::new(&env, &contract_id); 39 | 40 | // When 41 | client.initialize(&u32::MAX); 42 | client.mul(&2); 43 | 44 | // Then 45 | // Panic 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test-cases/integer-overflow-or-underflow/integer-overflow-or-underflow-4/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, symbol_short, Env, Symbol}; 4 | 5 | #[contract] 6 | pub struct IntegerOverflowUnderflow; 7 | 8 | #[contractimpl] 9 | impl IntegerOverflowUnderflow { 10 | const VALUE: Symbol = symbol_short!("VALUE"); 11 | 12 | pub fn initialize(env: Env, value: u32) { 13 | env.storage().temporary().set(&Self::VALUE, &value); 14 | } 15 | 16 | pub fn pow(env: Env, value: u32) { 17 | let current: u32 = env.storage().temporary().get(&Self::VALUE).unwrap_or(0); 18 | let new_value = current.pow(value); 19 | env.storage().temporary().set(&Self::VALUE, &new_value); 20 | } 21 | 22 | pub fn get(env: Env) -> u32 { 23 | env.storage().temporary().get(&Self::VALUE).unwrap_or(0) 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod test { 29 | use super::*; 30 | use soroban_sdk::Env; 31 | 32 | #[test] 33 | #[should_panic(expected = "attempt to multiply with overflow")] 34 | fn test_pow_overflow() { 35 | // Given 36 | let env = Env::default(); 37 | let contract_id = env.register_contract(None, IntegerOverflowUnderflow); 38 | let client = IntegerOverflowUnderflowClient::new(&env, &contract_id); 39 | 40 | // When 41 | client.initialize(&2); 42 | client.pow(&u32::MAX); 43 | 44 | // Then 45 | // Panic 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-3/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn safe_unwrap(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | let mut return_value = 0; 19 | if result.is_ok() { 20 | return_value = result.unwrap(); 21 | } 22 | return_value 23 | } 24 | 25 | pub fn non_zero_or_error(n: u64) -> Result { 26 | if n == 0 { 27 | return Err(Error::CustomError); 28 | } 29 | Ok(n) 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use crate::UnsafeUnwrap; 36 | 37 | #[test] 38 | fn test_unwrap_zero() { 39 | // Given 40 | let test_value = 0; 41 | 42 | // When 43 | let result = UnsafeUnwrap::safe_unwrap(test_value); 44 | 45 | // Then 46 | assert_eq!(result, test_value); 47 | } 48 | 49 | #[test] 50 | fn test_unwrap_non_zero() { 51 | // Given 52 | let test_value = 100; 53 | 54 | // When 55 | let result = UnsafeUnwrap::safe_unwrap(test_value); 56 | 57 | // Then 58 | assert_eq!(result, test_value); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /docs/docs/vulnerabilities/7-avoid-core-mem-forget.md: -------------------------------------------------------------------------------- 1 | # Avoid core::mem::forget usage 2 | 3 | ## Description 4 | 5 | - Vulnerability Category: `Best practices` 6 | - Vulnerability Severity: `Enhancement` 7 | - Detectors: [`avoid-core-mem-forget`](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/avoid-core-mem-forget) 8 | - Test Cases: [`avoid-core-mem-forget-1`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1) 9 | 10 | The `core::mem::forget` function usage is a bad practice. 11 | 12 | ## Exploit Scenario 13 | 14 | Consider the following `Soroban` contract: 15 | 16 | ```rust 17 | pub fn forget_something(n: WithoutCopy) -> u64 { 18 | core::mem::forget(n); 19 | 0 20 | } 21 | ``` 22 | 23 | The problem arises from the use of the `core::mem::forget` function. This function is used to forget about a value without running its destructor. This is a bad practice because it can lead to memory leaks, resource leaks and logic errors. 24 | 25 | The vulnerable code example can be found [`here`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/vulnerable-example). 26 | 27 | ## Remediation 28 | 29 | Use the pattern `let _ = n;` or the `.drop()` method instead of `core::mem::forget(n);`. 30 | 31 | ## References 32 | 33 | - [Memory Management](https://docs.alephzero.org/aleph-zero/security-course-by-kudelski-security/ink-developers-security-guideline#memory-management) 34 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-4/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn unwrap(n: u64) -> (u64, u64) { 17 | let result = Self::non_zero_or_error(n); 18 | (result.unwrap(), result.unwrap()) 19 | } 20 | 21 | pub fn non_zero_or_error(n: u64) -> Result { 22 | if n == 0 { 23 | return Err(Error::CustomError); 24 | } 25 | Ok(n) 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use crate::UnsafeUnwrap; 32 | 33 | #[test] 34 | #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: CustomError")] 35 | fn test_unwrap_zero() { 36 | // Given 37 | let test_value = 0; 38 | 39 | // When 40 | let _result = UnsafeUnwrap::unwrap(test_value); 41 | 42 | // Then 43 | // The test should panic 44 | } 45 | 46 | #[test] 47 | fn test_unwrap_non_zero() { 48 | // Given 49 | let test_value = 100; 50 | 51 | // When 52 | let result = UnsafeUnwrap::unwrap(test_value); 53 | 54 | // Then 55 | assert_eq!(result.0, test_value); 56 | assert_eq!(result.1, test_value); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, Address, Env}; 4 | 5 | #[contract] 6 | pub struct SetContractStorage; 7 | 8 | #[contractimpl] 9 | impl SetContractStorage { 10 | /// Increment an internal counter; return the new value. 11 | pub fn increment(env: Env, user: Address) -> u32 { 12 | let storage = env.storage().instance(); 13 | let mut count: u32 = storage.get(&user).unwrap_or_default(); 14 | count += 1; 15 | storage.set(&user, &count); 16 | storage.extend_ttl(100, 100); 17 | count 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use soroban_sdk::{testutils, Address, Env}; 24 | 25 | use crate::{SetContractStorage, SetContractStorageClient}; 26 | 27 | #[test] 28 | fn increment() { 29 | // Given 30 | let env = Env::default(); 31 | let contract_id = env.register_contract(None, SetContractStorage); 32 | let client = SetContractStorageClient::new(&env, &contract_id); 33 | let user =
::generate(&env); 34 | 35 | // When 36 | let first_increment = client.increment(&user); 37 | let second_increment = client.increment(&user); 38 | let third_increment = client.increment(&user); 39 | 40 | // Then 41 | assert_eq!(first_increment, 1); 42 | assert_eq!(second_increment, 2); 43 | assert_eq!(third_increment, 3); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test-cases/assert-violation/assert-violation-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, Env, Symbol}; 4 | 5 | #[derive(Debug, Clone)] 6 | #[contracttype] 7 | pub struct State { 8 | value: u128, 9 | } 10 | 11 | const STATE: Symbol = symbol_short!("STATE"); 12 | #[contract] 13 | pub struct AssertViolation; 14 | 15 | #[contractimpl] 16 | impl AssertViolation { 17 | pub fn init(env: Env, init_value: u128) -> State { 18 | let state = State { value: init_value }; 19 | 20 | env.storage().instance().set(&STATE, &state); 21 | state 22 | } 23 | 24 | pub fn assert_if_greater_than_10(_env: Env, value: u128) -> bool { 25 | assert!(value <= 10, "value should be less than 10"); 26 | true 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | 34 | #[test] 35 | fn does_not_revert_if_greater() { 36 | let env = Env::default(); 37 | let contract = 38 | AssertViolationClient::new(&env, &env.register_contract(None, AssertViolation {})); 39 | assert!(contract.assert_if_greater_than_10(&5)); 40 | } 41 | 42 | #[test] 43 | #[should_panic(expected = "value should be less than 10")] 44 | fn reverts_if_greater() { 45 | let env = Env::default(); 46 | let contract = 47 | AssertViolationClient::new(&env, &env.register_contract(None, AssertViolation {})); 48 | contract.assert_if_greater_than_10(&11); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-2/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, Address, Env}; 4 | 5 | #[contract] 6 | pub struct SetContractStorage; 7 | 8 | #[contractimpl] 9 | impl SetContractStorage { 10 | /// Increment an internal counter; return the new value. 11 | pub fn increment(env: Env, user: Address) -> u32 { 12 | let storage = env.storage().temporary(); 13 | let mut count: u32 = storage.get(&user).unwrap_or_default(); 14 | count += 1; 15 | storage.set(&user, &count); 16 | storage.extend_ttl(&user, 100, 100); 17 | count 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use soroban_sdk::{testutils, Address, Env}; 24 | 25 | use crate::{SetContractStorage, SetContractStorageClient}; 26 | 27 | #[test] 28 | fn increment() { 29 | // Given 30 | let env = Env::default(); 31 | let contract_id = env.register_contract(None, SetContractStorage); 32 | let client = SetContractStorageClient::new(&env, &contract_id); 33 | let user =
::generate(&env); 34 | 35 | // When 36 | let first_increment = client.increment(&user); 37 | let second_increment = client.increment(&user); 38 | let third_increment = client.increment(&user); 39 | 40 | // Then 41 | assert_eq!(first_increment, 1); 42 | assert_eq!(second_increment, 2); 43 | assert_eq!(third_increment, 3); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-3/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, Address, Env}; 4 | 5 | #[contract] 6 | pub struct SetContractStorage; 7 | 8 | #[contractimpl] 9 | impl SetContractStorage { 10 | /// Increment an internal counter; return the new value. 11 | pub fn increment(env: Env, user: Address) -> u32 { 12 | let storage = env.storage().persistent(); 13 | let mut count: u32 = storage.get(&user).unwrap_or_default(); 14 | count += 1; 15 | storage.set(&user, &count); 16 | storage.extend_ttl(&user, 100, 100); 17 | count 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use soroban_sdk::{testutils, Address, Env}; 24 | 25 | use crate::{SetContractStorage, SetContractStorageClient}; 26 | 27 | #[test] 28 | fn increment() { 29 | // Given 30 | let env = Env::default(); 31 | let contract_id = env.register_contract(None, SetContractStorage); 32 | let client = SetContractStorageClient::new(&env, &contract_id); 33 | let user =
::generate(&env); 34 | 35 | // When 36 | let first_increment = client.increment(&user); 37 | let second_increment = client.increment(&user); 38 | let third_increment = client.increment(&user); 39 | 40 | // Then 41 | assert_eq!(first_increment, 1); 42 | assert_eq!(second_increment, 2); 43 | assert_eq!(third_increment, 3); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/docs/detectors/19-unsafe-map-get.md: -------------------------------------------------------------------------------- 1 | # Unsafe map get 2 | 3 | ### What it does 4 | 5 | This detector identifies instances where unsafe methods like `get`, `get_unchecked`, and `try_get_unchecked` are used on `Map` objects in Soroban smart contracts. 6 | 7 | ### Why is this bad? 8 | 9 | These methods are risky because they can lead to panics if the key does not exist in the map. Using these methods without proper checks increases the risk of runtime errors that can disrupt the execution of the smart contract and potentially lead to unexpected behavior or denial of service. 10 | 11 | ### Example 12 | 13 | ```rust 14 | pub fn get_from_map(env: Env) -> Option { 15 | let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env))]; 16 | let map: Val = map.into(); 17 | let map: Map = map.try_into_val(&env).unwrap(); 18 | map.get(1) 19 | } 20 | ``` 21 | 22 | Use instead: 23 | 24 | ```rust 25 | pub fn get_map_with_different_values(env: Env, key: i32) -> Result, Error> { 26 | let map: Map = map![ 27 | &env, 28 | (1i32.into_val(&env), 2i32.into_val(&env)), 29 | (3i32.into_val(&env), 4i64.into_val(&env)), 30 | ]; 31 | let map: Val = map.into(); 32 | let map: Map = map.try_into_val(&env).unwrap(); 33 | map.try_get(key).map_err(Error::from) 34 | } 35 | ``` 36 | 37 | ### Implementation 38 | 39 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/unsafe-map-get). 40 | 41 | -------------------------------------------------------------------------------- /docs/docs/detectors/14-iterators-over-indexing.md: -------------------------------------------------------------------------------- 1 | # Iterators-over-indexing 2 | 3 | ### What it does 4 | 5 | It warns if the for loop uses indexing instead of iterator. If the indexing goes to length it will not raise a warning. 6 | 7 | ### Why is this bad? 8 | 9 | 10 | Accessing a vector by index is slower than using an iterator. Also, if the index is out of bounds, it will panic. 11 | 12 | 13 | ### Example​ 14 | 15 | ```rust 16 | pub fn sum(e: Env) -> Result { 17 | let mut ret = 0_i32; 18 | let vec = e 19 | .storage() 20 | .instance() 21 | .get::>(&DataKey::Data) 22 | .ok_or(Error::NoData)?; 23 | for i in 0..4 { 24 | ret = ret 25 | .checked_add(vec.get(i).ok_or(Error::NoData)?) 26 | .ok_or(Error::IntegerOverflow)?; 27 | } 28 | Ok(ret) 29 | } 30 | ``` 31 | Use instead: 32 | ```rust 33 | pub fn sum(e: Env) -> Result { 34 | let mut ret = 0_i32; 35 | let vec = e 36 | .storage() 37 | .instance() 38 | .get::>(&DataKey::Data) 39 | .ok_or(Error::NoData)?; 40 | for i in vec { 41 | ret = ret.checked_add(i).ok_or(Error::IntegerOverflow)?; 42 | } 43 | Ok(ret) 44 | } 45 | ``` 46 | ### Implementation 47 | 48 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/iterators-over-indexing). 49 | 50 | -------------------------------------------------------------------------------- /test-cases/iterators-over-indexing/iterators-over-indexing-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl, contracttype, vec, Env, Vec}; 4 | 5 | #[contracttype] 6 | #[derive(Clone)] 7 | enum DataKey { 8 | Data, 9 | } 10 | 11 | #[contract] 12 | pub struct IteratorsOverIndexingVulnerableContract; 13 | 14 | #[contracterror] 15 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 16 | #[repr(u32)] 17 | pub enum Error { 18 | NoData = 1, 19 | IntegerOverflow = 2, 20 | } 21 | 22 | #[contractimpl] 23 | impl IteratorsOverIndexingVulnerableContract { 24 | pub fn init(e: Env) { 25 | e.storage() 26 | .instance() 27 | .set::>(&DataKey::Data, &vec![&e, 1_i32, 2_i32, 3_i32, 4_i32]); 28 | } 29 | 30 | pub fn sum(e: Env) -> Result { 31 | let mut ret = 0_i32; 32 | let vec = e 33 | .storage() 34 | .instance() 35 | .get::>(&DataKey::Data) 36 | .ok_or(Error::NoData)?; 37 | for i in vec { 38 | ret = ret.checked_add(i).ok_or(Error::IntegerOverflow)?; 39 | } 40 | Ok(ret) 41 | } 42 | } 43 | 44 | #[test] 45 | fn simple_test() { 46 | let e = Env::default(); 47 | e.mock_all_auths(); 48 | let client = IteratorsOverIndexingVulnerableContractClient::new( 49 | &e, 50 | &e.register_contract(None, IteratorsOverIndexingVulnerableContract {}), 51 | ); 52 | client.init(); 53 | assert_eq!(client.sum(), 10); 54 | } 55 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-2/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl}; 4 | 5 | #[contract] 6 | pub struct UnusedReturnEnum; 7 | 8 | #[contracterror] 9 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 10 | #[repr(u32)] 11 | pub enum Error { 12 | /// An overflow was produced. 13 | Overflow = 1, 14 | } 15 | 16 | #[contractimpl] 17 | impl UnusedReturnEnum { 18 | /// Returns the percentage difference between two values. 19 | pub fn get_percentage_difference(balance1: u128, balance2: u128) -> Result { 20 | let absolute_difference = balance1.abs_diff(balance2); 21 | let sum = balance1 + balance2; 22 | let result = 100u128 23 | .checked_mul(absolute_difference / sum) 24 | .ok_or(Error::Overflow)?; 25 | Ok(result) 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | 32 | use soroban_sdk::Env; 33 | 34 | use crate::{UnusedReturnEnum, UnusedReturnEnumClient}; 35 | 36 | #[test] 37 | fn get_percentage_difference_works() { 38 | // Given 39 | let env = Env::default(); 40 | let contract_id = env.register_contract(None, UnusedReturnEnum); 41 | let client = UnusedReturnEnumClient::new(&env, &contract_id); 42 | 43 | // When 44 | let value1 = 100u128; 45 | let value2 = 150u128; 46 | let result = client.try_get_percentage_difference(&value1, &value2); 47 | 48 | // Then 49 | assert_eq!(result, Ok(Ok(0))); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, Address, Env}; 3 | 4 | #[contract] 5 | pub struct SetContractStorage; 6 | 7 | #[contractimpl] 8 | impl SetContractStorage { 9 | /// Increment an internal counter; return the new value. 10 | pub fn increment(env: Env, user: Address) -> u32 { 11 | user.require_auth(); 12 | let storage = env.storage().instance(); 13 | let mut count: u32 = storage.get(&user).unwrap_or_default(); 14 | count += 1; 15 | storage.set(&user, &count); 16 | storage.extend_ttl(100, 100); 17 | count 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use soroban_sdk::{testutils, Address, Env}; 24 | 25 | use crate::{SetContractStorage, SetContractStorageClient}; 26 | 27 | #[test] 28 | fn increment() { 29 | // Given 30 | let env = Env::default(); 31 | let contract_id = env.register_contract(None, SetContractStorage); 32 | let client = SetContractStorageClient::new(&env, &contract_id); 33 | env.mock_all_auths(); 34 | let user =
::generate(&env); 35 | 36 | // When 37 | let first_increment = client.increment(&user); 38 | let second_increment = client.increment(&user); 39 | let third_increment = client.increment(&user); 40 | 41 | // Then 42 | assert_eq!(first_increment, 1); 43 | assert_eq!(second_increment, 2); 44 | assert_eq!(third_increment, 3); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-2/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, Address, Env}; 3 | 4 | #[contract] 5 | pub struct SetContractStorage; 6 | 7 | #[contractimpl] 8 | impl SetContractStorage { 9 | /// Increment an internal counter; return the new value. 10 | pub fn increment(env: Env, user: Address) -> u32 { 11 | user.require_auth(); 12 | let storage = env.storage().temporary(); 13 | let mut count: u32 = storage.get(&user).unwrap_or_default(); 14 | count += 1; 15 | storage.set(&user, &count); 16 | storage.extend_ttl(&user, 100, 100); 17 | count 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use soroban_sdk::{testutils, Address, Env}; 24 | 25 | use crate::{SetContractStorage, SetContractStorageClient}; 26 | 27 | #[test] 28 | fn increment() { 29 | // Given 30 | let env = Env::default(); 31 | let contract_id = env.register_contract(None, SetContractStorage); 32 | let client = SetContractStorageClient::new(&env, &contract_id); 33 | env.mock_all_auths(); 34 | let user =
::generate(&env); 35 | 36 | // When 37 | let first_increment = client.increment(&user); 38 | let second_increment = client.increment(&user); 39 | let third_increment = client.increment(&user); 40 | 41 | // Then 42 | assert_eq!(first_increment, 1); 43 | assert_eq!(second_increment, 2); 44 | assert_eq!(third_increment, 3); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "docs/**" 9 | workflow_dispatch: 10 | 11 | jobs: 12 | deploy: 13 | name: Deploy to GitHub Pages 14 | runs-on: ubuntu-latest 15 | defaults: 16 | run: 17 | working-directory: ./docs 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | 22 | - name: Set up Node.js 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: 20 26 | 27 | - uses: pnpm/action-setup@v3 28 | name: Install pnpm 29 | with: 30 | version: 9 31 | run_install: false 32 | 33 | - name: Get pnpm store directory 34 | id: pnpm-cache 35 | run: echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT 36 | 37 | - uses: actions/cache@v4 38 | name: Setup pnpm cache 39 | with: 40 | path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} 41 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('./docs/pnpm-lock.yaml') }} 42 | restore-keys: ${{ runner.os }}-pnpm-store- 43 | 44 | - name: Install dependencies 45 | run: pnpm install --frozen-lockfile 46 | 47 | - name: Build website 48 | run: pnpm build 49 | 50 | - name: Deploy to GitHub Pages 51 | uses: peaceiris/actions-gh-pages@v4 52 | with: 53 | github_token: ${{ secrets.GITHUB_TOKEN }} 54 | # Build output to publish to the `gh-pages` branch: 55 | publish_dir: ./docs/build 56 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-3/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contractimpl, Address, Env}; 3 | 4 | #[contract] 5 | pub struct SetContractStorage; 6 | 7 | #[contractimpl] 8 | impl SetContractStorage { 9 | /// Increment an internal counter; return the new value. 10 | pub fn increment(env: Env, user: Address) -> u32 { 11 | user.require_auth(); 12 | let storage = env.storage().persistent(); 13 | let mut count: u32 = storage.get(&user).unwrap_or_default(); 14 | count += 1; 15 | storage.set(&user, &count); 16 | storage.extend_ttl(&user, 100, 100); 17 | count 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use soroban_sdk::{testutils, Address, Env}; 24 | 25 | use crate::{SetContractStorage, SetContractStorageClient}; 26 | 27 | #[test] 28 | fn increment() { 29 | // Given 30 | let env = Env::default(); 31 | let contract_id = env.register_contract(None, SetContractStorage); 32 | let client = SetContractStorageClient::new(&env, &contract_id); 33 | env.mock_all_auths(); 34 | let user =
::generate(&env); 35 | 36 | // When 37 | let first_increment = client.increment(&user); 38 | let second_increment = client.increment(&user); 39 | let third_increment = client.increment(&user); 40 | 41 | // Then 42 | assert_eq!(first_increment, 1); 43 | assert_eq!(second_increment, 2); 44 | assert_eq!(third_increment, 3); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl}; 4 | 5 | #[contract] 6 | pub struct UnusedReturnEnum; 7 | 8 | #[contracterror] 9 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 10 | #[repr(u32)] 11 | pub enum Error { 12 | /// An overflow was produced. 13 | Overflow = 1, 14 | } 15 | 16 | #[contractimpl] 17 | impl UnusedReturnEnum { 18 | /// Returns the percentage difference between two values. 19 | pub fn get_percentage_difference(balance1: u128, balance2: u128) -> Result { 20 | let absolute_difference = balance1.abs_diff(balance2); 21 | let sum = balance1 + balance2; 22 | 23 | match 100u128.checked_mul(absolute_difference / sum) { 24 | Some(result) => Ok(result), 25 | None => Err(Error::Overflow), 26 | } 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | 33 | use soroban_sdk::Env; 34 | 35 | use crate::{UnusedReturnEnum, UnusedReturnEnumClient}; 36 | 37 | #[test] 38 | fn get_percentage_difference_works() { 39 | // Given 40 | let env = Env::default(); 41 | let contract_id = env.register_contract(None, UnusedReturnEnum); 42 | let client = UnusedReturnEnumClient::new(&env, &contract_id); 43 | 44 | // When 45 | let value1 = 100u128; 46 | let value2 = 150u128; 47 | let result = client.try_get_percentage_difference(&value1, &value2); 48 | 49 | // Then 50 | assert_eq!(result, Ok(Ok(0))); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /templates/detector/early-lint/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | extern crate rustc_ast; 4 | extern crate rustc_span; 5 | 6 | use rustc_ast::visit::{FnKind, Visitor}; 7 | use rustc_ast::{Expr, ExprKind}; 8 | use rustc_lint::{EarlyContext, EarlyLintPass}; 9 | use rustc_span::Span; 10 | use scout_audit_clippy_utils::diagnostics::span_lint_and_help; 11 | 12 | dylint_linting::declare_early_lint! { 13 | /// ### What it does 14 | /// Describe what the lint does. 15 | /// 16 | /// ### Why is this bad? 17 | /// Describe why the linted code is considered bad. 18 | /// 19 | /// ### Example 20 | /// ```rust 21 | /// // example code where a warning is issued 22 | /// ``` 23 | /// Use instead: 24 | /// ```rust 25 | /// // example code that does not raise a warning 26 | /// ``` 27 | pub YOUR_LINT_NAME, 28 | Warn, 29 | "Short description of the lint" 30 | } 31 | 32 | struct YourVisitor { 33 | // Add any fields necessary for your lint 34 | } 35 | 36 | impl<'ast> Visitor<'ast> for YourVisitor { 37 | fn visit_expr(&mut self, ex: &'ast Expr) { 38 | // Implement the logic of your lint here 39 | 40 | // Call `walk_expr` to visit the descendants of `ex` 41 | rustc_ast::visit::walk_expr(self, ex); 42 | } 43 | } 44 | 45 | impl EarlyLintPass for YourLint { 46 | fn check_fn( 47 | &mut self, 48 | cx: &EarlyContext<'_>, 49 | fn_kind: FnKind<'_>, 50 | _: Span, 51 | _: rustc_ast::NodeId, 52 | ) { 53 | // Implement check_fn and emit any necessary diagnostic messages 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /docs/docs/detectors/9-avoid-panic-error.md: -------------------------------------------------------------------------------- 1 | # Panic error 2 | 3 | ### What it does 4 | 5 | The `panic!` macro is used to stop execution when a condition is not met. 6 | This is useful for testing and prototyping, but should be avoided in production code. 7 | 8 | ### Why is this bad? 9 | 10 | The usage of `panic!` is not recommended because it will stop the execution of the caller contract. 11 | 12 | ### Known problems 13 | 14 | While this linter detects explicit calls to `panic!`, there are some ways to raise a panic such as `unwrap()` or `expect()`. 15 | 16 | ### Example 17 | 18 | ```rust 19 | pub fn add(env: Env, value: u32) -> u32 { 20 | let storage = env.storage().instance(); 21 | let mut count: u32 = storage.get(&COUNTER).unwrap_or(0); 22 | match count.checked_add(value) { 23 | Some(value) => count = value, 24 | None => panic!("Overflow error"), 25 | } 26 | storage.set(&COUNTER, &count); 27 | storage.extend_ttl(100, 100); 28 | count 29 | } 30 | ``` 31 | 32 | Use instead: 33 | 34 | ```rust 35 | pub fn add(env: Env, value: u32) -> Result { 36 | let storage = env.storage().instance(); 37 | let mut count: u32 = storage.get(&COUNTER).unwrap_or(0); 38 | match count.checked_add(value) { 39 | Some(value) => count = value, 40 | None => return Err(Error::OverflowError), 41 | } 42 | storage.set(&COUNTER, &count); 43 | storage.extend_ttl(100, 100); 44 | Ok(count) 45 | } 46 | ``` 47 | 48 | ### Implementation 49 | 50 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/avoid-panic-error). -------------------------------------------------------------------------------- /test-cases/incorrect-exponentiation/incorrect-exponentiation-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Env}; 4 | 5 | #[contracterror] 6 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 7 | #[repr(u32)] 8 | pub enum IEError { 9 | CouldntRetrieveData = 1, 10 | } 11 | 12 | #[contracttype] 13 | #[derive(Clone)] 14 | enum DataKey { 15 | Data, 16 | } 17 | 18 | #[contract] 19 | pub struct IncorrectExponentiation; 20 | 21 | #[contractimpl] 22 | impl IncorrectExponentiation { 23 | pub fn init(e: Env) { 24 | e.storage() 25 | .instance() 26 | .set::(&DataKey::Data, &((255_u128 ^ 2) - 1)); 27 | } 28 | 29 | pub fn get_data(e: Env) -> Result { 30 | let data = e.storage().instance().get(&DataKey::Data); 31 | match data { 32 | Some(x) => Ok(x), 33 | None => Err(IEError::CouldntRetrieveData), 34 | } 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use soroban_sdk::{testutils, Address, Env}; 41 | 42 | use crate::{IncorrectExponentiation, IncorrectExponentiationClient}; 43 | 44 | #[test] 45 | fn simple_test() { 46 | let env = Env::default(); 47 | let contract_id = env.register_contract(None, IncorrectExponentiation); 48 | let client = IncorrectExponentiationClient::new(&env, &contract_id); 49 | env.mock_all_auths(); 50 | let _user =
::generate(&env); 51 | 52 | client.init(); 53 | assert_ne!(client.get_data(), 65024); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test-cases/incorrect-exponentiation/incorrect-exponentiation-1/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Env}; 4 | 5 | #[contracterror] 6 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 7 | #[repr(u32)] 8 | pub enum IEError { 9 | CouldntRetrieveData = 1, 10 | } 11 | 12 | #[contracttype] 13 | #[derive(Clone)] 14 | enum DataKey { 15 | Data, 16 | } 17 | 18 | #[contract] 19 | pub struct IncorrectExponentiation; 20 | 21 | #[contractimpl] 22 | impl IncorrectExponentiation { 23 | pub fn init(e: Env) { 24 | e.storage() 25 | .instance() 26 | .set::(&DataKey::Data, &(255_u128.pow(2) - 1)); 27 | } 28 | 29 | pub fn get_data(e: Env) -> Result { 30 | let data = e.storage().instance().get(&DataKey::Data); 31 | match data { 32 | Some(x) => Ok(x), 33 | None => Err(IEError::CouldntRetrieveData), 34 | } 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use soroban_sdk::{testutils, Address, Env}; 41 | 42 | use crate::{IncorrectExponentiation, IncorrectExponentiationClient}; 43 | 44 | #[test] 45 | fn simple_test() { 46 | let env = Env::default(); 47 | let contract_id = env.register_contract(None, IncorrectExponentiation); 48 | let client = IncorrectExponentiationClient::new(&env, &contract_id); 49 | env.mock_all_auths(); 50 | let _user =
::generate(&env); 51 | 52 | client.init(); 53 | assert_eq!(client.get_data(), 65024); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test-cases/iterators-over-indexing/iterators-over-indexing-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl, contracttype, vec, Env, Vec}; 4 | 5 | #[contracttype] 6 | #[derive(Clone)] 7 | enum DataKey { 8 | Data, 9 | } 10 | 11 | #[contract] 12 | pub struct IteratorsOverIndexingVulnerableContract; 13 | 14 | #[contracterror] 15 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 16 | #[repr(u32)] 17 | pub enum Error { 18 | NoData = 1, 19 | IntegerOverflow = 2, 20 | } 21 | 22 | #[contractimpl] 23 | impl IteratorsOverIndexingVulnerableContract { 24 | pub fn init(e: Env) { 25 | e.storage() 26 | .instance() 27 | .set::>(&DataKey::Data, &vec![&e, 1_i32, 2_i32, 3_i32, 4_i32]); 28 | } 29 | 30 | pub fn sum(e: Env) -> Result { 31 | let mut ret = 0_i32; 32 | let vec = e 33 | .storage() 34 | .instance() 35 | .get::>(&DataKey::Data) 36 | .ok_or(Error::NoData)?; 37 | for i in 0..4 { 38 | ret = ret 39 | .checked_add(vec.get(i).ok_or(Error::NoData)?) 40 | .ok_or(Error::IntegerOverflow)?; 41 | } 42 | Ok(ret) 43 | } 44 | } 45 | 46 | #[test] 47 | fn simple_test() { 48 | let e = Env::default(); 49 | e.mock_all_auths(); 50 | let client = IteratorsOverIndexingVulnerableContractClient::new( 51 | &e, 52 | &e.register_contract(None, IteratorsOverIndexingVulnerableContract {}), 53 | ); 54 | client.init(); 55 | assert_eq!(client.sum(), 10); 56 | } 57 | -------------------------------------------------------------------------------- /scripts/run-fmt.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import time 4 | 5 | from utils import print_errors, print_results, run_subprocess, is_rust_project 6 | 7 | GREEN = "\033[92m" 8 | ENDC = "\033[0m" 9 | 10 | 11 | def run_fmt(directories): 12 | errors = [] 13 | for directory in directories: 14 | if not os.path.isdir(directory): 15 | errors.append( 16 | f"Error: The specified path '{directory}' is not a directory or does not exist." 17 | ) 18 | continue 19 | 20 | print(f"\n{GREEN}Checking format in {directory}:{ENDC}") 21 | for root, _, _ in os.walk(directory): 22 | if is_rust_project(root): 23 | start_time = time.time() 24 | returncode, _, stderr = run_subprocess( 25 | ["cargo", "fmt", "--check"], 26 | cwd=root, 27 | ) 28 | print_results( 29 | returncode, stderr, "format", root, time.time() - start_time 30 | ) 31 | if returncode != 0: 32 | errors.append(root) 33 | return errors 34 | 35 | 36 | if __name__ == "__main__": 37 | parser = argparse.ArgumentParser( 38 | description="Run cargo-fmt for specified directories" 39 | ) 40 | parser.add_argument( 41 | "--dir", 42 | nargs="+", 43 | required=True, 44 | help="Specify the directories to run cargo-fmt on. Multiple directories can be specified.", 45 | ) 46 | args = parser.parse_args() 47 | 48 | errors = run_fmt(args.dir) 49 | print_errors(errors) 50 | if errors: 51 | exit(1) 52 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-1/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl}; 4 | 5 | #[contract] 6 | pub struct UnusedReturnEnum; 7 | 8 | #[contracterror] 9 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 10 | #[repr(u32)] 11 | pub enum Error { 12 | /// An overflow was produced. 13 | Overflow = 1, 14 | } 15 | 16 | #[contractimpl] 17 | impl UnusedReturnEnum { 18 | /// Returns the percentage difference between two values. 19 | pub fn get_percentage_difference(balance1: u128, balance2: u128) -> Result { 20 | let absolute_difference = balance1.abs_diff(balance2); 21 | let sum = balance1 + balance2; 22 | 23 | match 100u128.checked_mul(absolute_difference / sum) { 24 | Some(result) => result, 25 | None => panic!("Overflow"), 26 | }; 27 | 28 | Err(Error::Overflow) 29 | } 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | 35 | use soroban_sdk::Env; 36 | 37 | use crate::{Error, UnusedReturnEnum, UnusedReturnEnumClient}; 38 | 39 | #[test] 40 | fn get_percentage_difference_panics() { 41 | // Given 42 | let env = Env::default(); 43 | let contract_id = env.register_contract(None, UnusedReturnEnum); 44 | let client = UnusedReturnEnumClient::new(&env, &contract_id); 45 | 46 | // When 47 | let value1 = 100u128; 48 | let value2 = 150u128; 49 | let result = client.try_get_percentage_difference(&value1, &value2); 50 | 51 | // Then 52 | assert_eq!(result, Err(Ok(Error::Overflow))); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test-cases/unused-return-enum/unused-return-enum-2/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contracterror, contractimpl}; 4 | 5 | #[contract] 6 | pub struct UnusedReturnEnum; 7 | 8 | #[contracterror] 9 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 10 | #[repr(u32)] 11 | pub enum Error { 12 | /// An overflow was produced. 13 | Overflow = 1, 14 | } 15 | 16 | #[contractimpl] 17 | impl UnusedReturnEnum { 18 | /// Returns the percentage difference between two values. 19 | pub fn get_percentage_difference(balance1: u128, balance2: u128) -> Result { 20 | let absolute_difference = balance1.abs_diff(balance2); 21 | let sum = balance1 + balance2; 22 | 23 | match 100u128.checked_mul(absolute_difference / sum) { 24 | Some(result) => result, 25 | None => panic!("Overflow"), 26 | }; 27 | 28 | Err(Error::Overflow) 29 | } 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | 35 | use soroban_sdk::Env; 36 | 37 | use crate::{Error, UnusedReturnEnum, UnusedReturnEnumClient}; 38 | 39 | #[test] 40 | fn get_percentage_difference_panics() { 41 | // Given 42 | let env = Env::default(); 43 | let contract_id = env.register_contract(None, UnusedReturnEnum); 44 | let client = UnusedReturnEnumClient::new(&env, &contract_id); 45 | 46 | // When 47 | let value1 = 100u128; 48 | let value2 = 150u128; 49 | let result = client.try_get_percentage_difference(&value1, &value2); 50 | 51 | // Then 52 | assert_eq!(result, Err(Ok(Error::Overflow))); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/run-udeps.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import subprocess 4 | import time 5 | 6 | from utils import print_errors, print_results, is_rust_project 7 | 8 | GREEN = "\033[92m" 9 | ENDC = "\033[0m" 10 | 11 | 12 | def run_udeps(directories): 13 | errors = [] 14 | for directory in directories: 15 | if not os.path.isdir(directory): 16 | errors.append( 17 | f"Error: The specified path '{directory}' is not a directory or does not exist." 18 | ) 19 | continue 20 | 21 | print(f"\n{GREEN}Checking unused dependencies in {directory}:{ENDC}") 22 | for root, _, _ in os.walk(directory): 23 | if is_rust_project(root): 24 | start_time = time.time() 25 | returncode, _, stderr = subprocess.run( 26 | ["cargo", "udeps"], cwd=root, capture_output=True, text=True 27 | ) 28 | print_results( 29 | returncode, stderr, "udeps", root, time.time() - start_time 30 | ) 31 | if returncode != 0: 32 | errors.append(root) 33 | 34 | return errors 35 | 36 | 37 | if __name__ == "__main__": 38 | parser = argparse.ArgumentParser( 39 | description="Run cargo-udeps for specified directories" 40 | ) 41 | parser.add_argument( 42 | "--dir", 43 | nargs="+", 44 | required=True, 45 | help="Specify the directories to run cargo-udeps on. Multiple directories can be specified.", 46 | ) 47 | args = parser.parse_args() 48 | 49 | errors = run_udeps(args.dir) 50 | print_errors(errors) 51 | if errors: 52 | exit(1) 53 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-5/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn safe_unwrap(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | if result.is_err() { 19 | return 0; 20 | } 21 | // Using result is now safe 22 | let first_operation = result.unwrap().checked_mul(2); 23 | if first_operation.is_none() { 24 | return 0; 25 | } 26 | // Using first_operation is now safe 27 | first_operation.unwrap() 28 | } 29 | 30 | pub fn non_zero_or_error(n: u64) -> Result { 31 | if n == 0 { 32 | return Err(Error::CustomError); 33 | } 34 | Ok(n) 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use crate::UnsafeUnwrap; 41 | 42 | #[test] 43 | fn test_unwrap_zero() { 44 | // Given 45 | let test_value = 0; 46 | 47 | // When 48 | let result = UnsafeUnwrap::safe_unwrap(test_value); 49 | 50 | // Then 51 | assert_eq!(result, test_value); 52 | } 53 | 54 | #[test] 55 | fn test_unwrap_non_zero() { 56 | // Given 57 | let test_value = 100; 58 | 59 | // When 60 | let result = UnsafeUnwrap::safe_unwrap(test_value); 61 | 62 | // Then 63 | assert_eq!(result, test_value * 2); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-5/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn unwrap(n: u64) -> u64 { 17 | let result = Self::non_zero_or_error(n); 18 | // Using result is unsafe 19 | let first_operation = result.unwrap().checked_mul(2); 20 | if first_operation.is_none() { 21 | return 0; 22 | } 23 | // Using first_operation is now safe 24 | first_operation.unwrap() 25 | } 26 | 27 | pub fn non_zero_or_error(n: u64) -> Result { 28 | if n == 0 { 29 | return Err(Error::CustomError); 30 | } 31 | Ok(n) 32 | } 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use crate::UnsafeUnwrap; 38 | 39 | #[test] 40 | #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: CustomError")] 41 | fn test_unwrap_zero() { 42 | // Given 43 | let test_value = 0; 44 | 45 | // When 46 | let _result = UnsafeUnwrap::unwrap(test_value); 47 | 48 | // Then 49 | // The test should panic 50 | } 51 | 52 | #[test] 53 | fn test_unwrap_non_zero() { 54 | // Given 55 | let test_value = 100; 56 | 57 | // When 58 | let result = UnsafeUnwrap::unwrap(test_value); 59 | 60 | // Then 61 | assert_eq!(result, test_value * 2); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/docs/vulnerabilities/12-soroban-version.md: -------------------------------------------------------------------------------- 1 | # Soroban version 2 | 3 | ## Description 4 | 5 | - Vulnerability Category: `Best practices` 6 | - Vulnerability Severity: `Enhacement` 7 | - Detectors: [`soroban-version`](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/soroban-version) 8 | - Test Cases: [`soroban-version-1`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/soroban-version/soroban-version-1) 9 | 10 | Using an old version of Soroban can be dangerous, as it may have bugs or security issues. Use the latest version available. 11 | 12 | ## Exploit Scenario 13 | 14 | Consider the following `Cargo.toml`: 15 | 16 | ```toml 17 | [dependencies] 18 | soroban-sdk = { version = "=19.0.0" } 19 | 20 | [dev_dependencies] 21 | soroban-sdk = { version = "=19.0.0", features = ["testutils"] } 22 | ``` 23 | 24 | Problems can arise if the version is not updated to the latest available. 25 | 26 | The vulnerable code example can be found [`here`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/soroban-version/soroban-version-1/vulnerable-example). 27 | 28 | ## Remediation 29 | 30 | ```toml 31 | [dependencies] 32 | // Use the latest version available. 33 | soroban-sdk = { workspace = true } 34 | 35 | [dev_dependencies] 36 | soroban-sdk = { workspace = true, features = ["testutils"] } 37 | ``` 38 | 39 | The remediated code example can be found [`here`](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases/soroban-version/soroban-version-1/remediated-example). 40 | 41 | ## References 42 | 43 | - [Floating Pragma](https://swcregistry.io/docs/SWC-103/) 44 | - [outdated Compiler Version](https://swcregistry.io/docs/SWC-102/) -------------------------------------------------------------------------------- /docs/docs/detectors/5-insufficiently-random-values.md: -------------------------------------------------------------------------------- 1 | # Insuficciently random values 2 | 3 | ### What it does 4 | Checks the usage of `ledger().timestamp()` or `ledger().sequence()` for generation of random numbers. 5 | 6 | ### Why is this bad? 7 | Using `ledger().timestamp()` is not recommended because it could be potentially manipulated by validator. On the other hand, `ledger().sequence()` is publicly available, an attacker could predict the random number to be generated. 8 | 9 | ### Example 10 | 11 | ```rust 12 | #[contractimpl] 13 | impl Contract { 14 | pub fn generate_random_value_timestamp(env: Env, max_val: u64) -> Result { 15 | if max_val == 0 { 16 | Err(Error::MaxValZero) 17 | } else { 18 | let val = env.ledger().timestamp() % max_val; 19 | Ok(val) 20 | } 21 | } 22 | pub fn generate_random_value_sequence(env: Env, max_val: u32) -> Result { 23 | if max_val == 0 { 24 | Err(Error::MaxValZero) 25 | } else { 26 | let val = env.ledger().sequence() % max_val; 27 | Ok(val) 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | Use instead: 34 | 35 | ```rust 36 | #[contractimpl] 37 | impl Contract { 38 | pub fn generate_random_value(env: Env, max_val: u64) -> Result { 39 | if max_val == 0 { 40 | Err(Error::MaxValZero) 41 | } else { 42 | let val = env.prng().u64_in_range(0..max_val); 43 | Ok(val) 44 | } 45 | } 46 | } 47 | ``` 48 | 49 | ### Implementation 50 | 51 | The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/insufficiently-random-values). -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-4/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use soroban_sdk::{contract, contracterror, contractimpl}; 3 | 4 | #[contract] 5 | pub struct UnsafeUnwrap; 6 | 7 | #[contracterror] 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 9 | #[repr(u32)] 10 | pub enum Error { 11 | CustomError = 1, 12 | } 13 | 14 | #[contractimpl] 15 | impl UnsafeUnwrap { 16 | pub fn safe_unwrap(n: u64) -> (u64, u64) { 17 | // We get the same element twice for demonstration purposes 18 | let result_1 = Self::non_zero_or_error(n); 19 | let result_2 = Self::non_zero_or_error(n); 20 | if result_1.is_err() || result_2.is_err() { 21 | return (0, 0); 22 | } 23 | (result_1.unwrap(), result_2.unwrap()) 24 | } 25 | 26 | pub fn non_zero_or_error(n: u64) -> Result { 27 | if n == 0 { 28 | return Err(Error::CustomError); 29 | } 30 | Ok(n) 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use crate::UnsafeUnwrap; 37 | 38 | #[test] 39 | fn test_unwrap_zero() { 40 | // Given 41 | let test_value = 0; 42 | 43 | // When 44 | let result = UnsafeUnwrap::safe_unwrap(test_value); 45 | 46 | // Then 47 | assert_eq!(result.0, test_value); 48 | assert_eq!(result.1, test_value); 49 | } 50 | 51 | #[test] 52 | fn test_unwrap_non_zero() { 53 | // Given 54 | let test_value = 100; 55 | 56 | // When 57 | let result = UnsafeUnwrap::safe_unwrap(test_value); 58 | 59 | // Then 60 | assert_eq!(result.0, test_value); 61 | assert_eq!(result.1, test_value); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-6/remediated-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(clippy::unnecessary_literal_unwrap)] 3 | 4 | use soroban_sdk::{contract, contracterror, contractimpl}; 5 | 6 | #[contract] 7 | pub struct UnsafeUnwrap; 8 | 9 | #[contracterror] 10 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 11 | #[repr(u32)] 12 | pub enum Error { 13 | CustomError = 1, 14 | } 15 | 16 | #[contractimpl] 17 | impl UnsafeUnwrap { 18 | pub fn safe_unwrap(n: u64) -> u64 { 19 | let result = Self::non_zero_or_error(n); 20 | if result.is_err() { 21 | return 0; 22 | } 23 | let known_value = Some(1u64); 24 | let first_operation = known_value.unwrap().checked_mul(result.unwrap()); 25 | if let Some(first_operation) = first_operation { 26 | return first_operation; 27 | } 28 | 0 29 | } 30 | 31 | pub fn non_zero_or_error(n: u64) -> Result { 32 | if n == 0 { 33 | return Err(Error::CustomError); 34 | } 35 | Ok(n) 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use crate::UnsafeUnwrap; 42 | 43 | #[test] 44 | fn test_unwrap_zero() { 45 | // Given 46 | let test_value = 0; 47 | 48 | // When 49 | let result = UnsafeUnwrap::safe_unwrap(test_value); 50 | 51 | // Then 52 | assert_eq!(result, test_value); 53 | } 54 | 55 | #[test] 56 | fn test_unwrap_non_zero() { 57 | // Given 58 | let test_value = 100; 59 | 60 | // When 61 | let result = UnsafeUnwrap::safe_unwrap(test_value); 62 | 63 | // Then 64 | assert_eq!(result, test_value); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test-cases/unsafe-unwrap/unsafe-unwrap-6/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(clippy::unnecessary_literal_unwrap)] 3 | 4 | use soroban_sdk::{contract, contracterror, contractimpl}; 5 | 6 | #[contract] 7 | pub struct UnsafeUnwrap; 8 | 9 | #[contracterror] 10 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 11 | #[repr(u32)] 12 | pub enum Error { 13 | CustomError = 1, 14 | } 15 | 16 | #[contractimpl] 17 | impl UnsafeUnwrap { 18 | pub fn unwrap(n: u64) -> u64 { 19 | let result = Self::non_zero_or_error(n); 20 | let known_value = Some(1u64); 21 | let first_operation = known_value.unwrap().checked_mul(result.unwrap()); 22 | if let Some(first_operation) = first_operation { 23 | return first_operation; 24 | } 25 | 0 26 | } 27 | 28 | pub fn non_zero_or_error(n: u64) -> Result { 29 | if n == 0 { 30 | return Err(Error::CustomError); 31 | } 32 | Ok(n) 33 | } 34 | } 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use crate::UnsafeUnwrap; 39 | 40 | #[test] 41 | #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: CustomError")] 42 | fn test_unwrap_zero() { 43 | // Given 44 | let test_value = 0; 45 | 46 | // When 47 | let _result = UnsafeUnwrap::unwrap(test_value); 48 | 49 | // Then 50 | // The test should panic 51 | } 52 | 53 | #[test] 54 | fn test_unwrap_non_zero() { 55 | // Given 56 | let test_value = 100; 57 | 58 | // When 59 | let result = UnsafeUnwrap::unwrap(test_value); 60 | 61 | // Then 62 | assert_eq!(result, test_value); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test-cases/set-contract-storage/set-contract-storage-4/vulnerable-example/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use soroban_sdk::{contract, contractimpl, Address, Env}; 4 | 5 | #[contract] 6 | pub struct SetContractStorage; 7 | 8 | #[contractimpl] 9 | impl SetContractStorage { 10 | /// Increment an internal counter; return the new value. 11 | pub fn unsafe_increment(env: Env, user: Address) -> u32 { 12 | utils::increment(env, user) 13 | } 14 | } 15 | 16 | mod utils { 17 | use soroban_sdk::{Address, Env}; 18 | 19 | pub fn increment(env: Env, user: Address) -> u32 { 20 | let storage = env.storage().persistent(); 21 | let mut count: u32 = storage.get(&user).unwrap_or_default(); 22 | count += 1; 23 | storage.set(&user, &count); 24 | storage.extend_ttl(&user, 100, 100); 25 | count 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use soroban_sdk::{testutils, Address, Env}; 32 | 33 | use crate::{SetContractStorage, SetContractStorageClient}; 34 | 35 | #[test] 36 | fn increment() { 37 | // Given 38 | let env = Env::default(); 39 | let contract_id = env.register_contract(None, SetContractStorage); 40 | let client = SetContractStorageClient::new(&env, &contract_id); 41 | let user =
::generate(&env); 42 | 43 | // When 44 | let first_increment = client.unsafe_increment(&user); 45 | let second_increment = client.unsafe_increment(&user); 46 | let third_increment = client.unsafe_increment(&user); 47 | 48 | // Then 49 | assert_eq!(first_increment, 1); 50 | assert_eq!(second_increment, 2); 51 | assert_eq!(third_increment, 3); 52 | } 53 | } 54 | --------------------------------------------------------------------------------