Corrections + new findings from live 2026-firmware P2S testing (signed commands, project_file)
Verified against a Bambu Lab P2S on 2026 firmware, cloud mode (X.509 app-cert route). Posting corrections to cloud-x509-auth.md plus several undocumented behaviors we confirmed live. Full write-up + tooling: https://github.com/Snail3D/bamboo-sense/blob/main/docs/CRACK.md
1. The signing canonicalization in cloud-x509-auth.md is wrong (sorted keys)
The doc's sorted-keys recipe does not verify. What actually works (confirmed by byte-level variant testing against the printer's error codes, and consistent with the decompiled signer in Randomblock1/bambu_connect_disasm):
- Sign
JSON.stringify(envelope_without_header) in original insertion order — "print" (or "security"/"system") object first, "user_id" trailing, outside the command object
sequence_id must be a number, not a string (string sequence_ids change the error signature)
header is then spliced in before the final } of the signed bytes: signed_bytes[:-1] + ',"header":{...}' + '}'
payload_len = UTF-8 byte length of the signed string
- sig = base64(RSA-SHA256 PKCS1v15 over the signed bytes)
- cert_id = 32-hex-char leaf serial + issuer CN, e.g.
5A5A…CN=GLOF3813734089.bambulab.com (issuer CN, not the leaf CN)
Useful error-code map (from the security result path):
| reason / shape |
meaning |
no header at all |
rejected before parsing |
0x05024009-family |
malformed envelope |
0x0502400A-family |
header present, signature doesn't verify (wrong canonical form, wrong cert_id, or cert not installed) |
2. print.project_file — fully working recipe + the URL gotcha nobody documents
{"print":{"sequence_id":<int>,"command":"project_file","param":"Metadata/plate_1.gcode",
"url":"<URL>","md5":"<md5 of the ENTIRE .3mf file>","project_id":"0","profile_id":"0",
"task_id":"0","subtask_id":"0","use_ams":true,"ams_mapping":[<tray idx>],
"bed_leveling":true,"flow_cali":false,"vibration_cali":true,"layer_inspect":true,
"timelapse":false},"user_id":"<uid>"}
md5 is the md5 of the whole 3mf file, NOT the Metadata/plate_1.gcode.md5 stored inside it. Wrong md5 ⇒ task aborts in PREPARE with print_error 83902527 (0x0500403F), before any heating.
url works as plaintext; url_enc (RSA to printer_cert) is accepted but not required on this firmware.
use_ams:false makes the printer pull from the external spool holder; if that's empty it fails with HMS_0300-0200 (filament ran out). ams_mapping = tray index list, one entry per filament.
The big one: url can be a plain LAN http:// URL on a cloud-mode printer
We started a real print on a cloud-mode (not LAN-only) P2S by handing project_file a bare http://192.168.x.x:8477/model.gcode.3mf served by a laptop. Printer did HEAD + GET and pulled 18.7 MB over LAN. Cloud-mode printer, zero Bambu cloud involvement, no SD card, no LAN-only mode.
The trap: presigned S3 URLs are rejected in PREPARE
Upload via v1/iot-service/api/user/upload (PUT 200) and hand the returned https://s3.us-west-2.amazonaws.com/or-cloud-upload-prod/...?AWSAccessKeyId=...&Signature=... URL to project_file: command is ACKed SUCCESS, printer shows PREPARE, then fails ~75 s later with print_error 83902527, no heating, HMS_0100-0100. Reproduced 3×. The firmware evidently only fetches from allow-listed hosts. If you see "ACK SUCCESS → PREPARE → FAILED 0x0500403F": it's the URL, not your signature/md5/AMS.
3. Undocumented print.clean_print_error command
{"print":{"command":"clean_print_error","sequence_id":N}} (signed normally) is accepted and clears the HMS alarm list (verified: HMS 0x10001 entry vanished). gcode_state remains FAILED as a sticky last-task-outcome field (same way FINISH persists). Notably, a LAN-url project_file still starts while gcode_state reads FAILED — the "ERROR STATE" refusals we saw were tied to the S3-url attempts, not to the latch. system.restart/system.reboot over MQTT are silently ignored.
4. State machine notes
- Signed
stop during RUNNING aborts instantly (verified at 238 °C nozzle).
stop from FINISH returns SUCCESS but is a no-op; resume from FAILED returns FAIL.
- New
project_file while FAILED: depends on URL validity — LAN urls launched fine, S3 urls got {"result":"FAIL","reason":"ERROR STATE"}.
Happy to turn any of this into PRs against the relevant docs if you want — the full recipe, scripts and the dongle implementation (ESP32-S3 signing vault that installs its own cert via app_cert_install and signs commands on-chip) are MIT-licensed at Snail3D/bamboo-sense.
Corrections + new findings from live 2026-firmware P2S testing (signed commands, project_file)
Verified against a Bambu Lab P2S on 2026 firmware, cloud mode (X.509 app-cert route). Posting corrections to
cloud-x509-auth.mdplus several undocumented behaviors we confirmed live. Full write-up + tooling: https://github.com/Snail3D/bamboo-sense/blob/main/docs/CRACK.md1. The signing canonicalization in cloud-x509-auth.md is wrong (sorted keys)
The doc's sorted-keys recipe does not verify. What actually works (confirmed by byte-level variant testing against the printer's error codes, and consistent with the decompiled signer in Randomblock1/bambu_connect_disasm):
JSON.stringify(envelope_without_header)in original insertion order —"print"(or"security"/"system") object first,"user_id"trailing, outside the command objectsequence_idmust be a number, not a string (string sequence_ids change the error signature)headeris then spliced in before the final}of the signed bytes:signed_bytes[:-1] + ',"header":{...}' + '}'payload_len= UTF-8 byte length of the signed string5A5A…CN=GLOF3813734089.bambulab.com(issuer CN, not the leaf CN)Useful error-code map (from the
securityresult path):headerat all0x05024009-family0x0502400A-family2.
print.project_file— fully working recipe + the URL gotcha nobody documents{"print":{"sequence_id":<int>,"command":"project_file","param":"Metadata/plate_1.gcode", "url":"<URL>","md5":"<md5 of the ENTIRE .3mf file>","project_id":"0","profile_id":"0", "task_id":"0","subtask_id":"0","use_ams":true,"ams_mapping":[<tray idx>], "bed_leveling":true,"flow_cali":false,"vibration_cali":true,"layer_inspect":true, "timelapse":false},"user_id":"<uid>"}md5is the md5 of the whole 3mf file, NOT theMetadata/plate_1.gcode.md5stored inside it. Wrong md5 ⇒ task aborts in PREPARE withprint_error83902527 (0x0500403F), before any heating.urlworks as plaintext;url_enc(RSA to printer_cert) is accepted but not required on this firmware.use_ams:falsemakes the printer pull from the external spool holder; if that's empty it fails with HMS_0300-0200 (filament ran out).ams_mapping= tray index list, one entry per filament.The big one:
urlcan be a plain LANhttp://URL on a cloud-mode printerWe started a real print on a cloud-mode (not LAN-only) P2S by handing
project_filea barehttp://192.168.x.x:8477/model.gcode.3mfserved by a laptop. Printer did HEAD + GET and pulled 18.7 MB over LAN. Cloud-mode printer, zero Bambu cloud involvement, no SD card, no LAN-only mode.The trap: presigned S3 URLs are rejected in PREPARE
Upload via
v1/iot-service/api/user/upload(PUT 200) and hand the returnedhttps://s3.us-west-2.amazonaws.com/or-cloud-upload-prod/...?AWSAccessKeyId=...&Signature=...URL toproject_file: command is ACKed SUCCESS, printer shows PREPARE, then fails ~75 s later withprint_error83902527, no heating, HMS_0100-0100. Reproduced 3×. The firmware evidently only fetches from allow-listed hosts. If you see "ACK SUCCESS → PREPARE → FAILED 0x0500403F": it's the URL, not your signature/md5/AMS.3. Undocumented
print.clean_print_errorcommand{"print":{"command":"clean_print_error","sequence_id":N}}(signed normally) is accepted and clears the HMS alarm list (verified: HMS 0x10001 entry vanished).gcode_stateremainsFAILEDas a sticky last-task-outcome field (same way FINISH persists). Notably, a LAN-urlproject_filestill starts whilegcode_statereads FAILED — the "ERROR STATE" refusals we saw were tied to the S3-url attempts, not to the latch.system.restart/system.rebootover MQTT are silently ignored.4. State machine notes
stopduring RUNNING aborts instantly (verified at 238 °C nozzle).stopfrom FINISH returns SUCCESS but is a no-op;resumefrom FAILED returns FAIL.project_filewhile FAILED: depends on URL validity — LAN urls launched fine, S3 urls got{"result":"FAIL","reason":"ERROR STATE"}.Happy to turn any of this into PRs against the relevant docs if you want — the full recipe, scripts and the dongle implementation (ESP32-S3 signing vault that installs its own cert via
app_cert_installand signs commands on-chip) are MIT-licensed at Snail3D/bamboo-sense.