[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-4-primitif-keamanan-kontrol-akses-reentrancy":3},{"article":4,"author":54},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":7,"meta_description":16,"focus_keyword":17,"og_image":18,"canonical_url":18,"robots_meta":19,"created_at":15,"updated_at":15,"tags":20,"category_name":34,"related_articles":35},"d2000000-0000-0000-0000-000000000104","a0000000-0000-0000-0000-000000000022","Deep EVM #4: Primitif Keamanan — msg.sender, Kontrol Akses, dan Reentrancy","deep-evm-4-primitif-keamanan-kontrol-akses-reentrancy","Keamanan smart contract di tingkat EVM: bagaimana msg.sender bekerja, pola kontrol akses, serangan reentrancy, dan teknik pertahanan menggunakan checks-effects-interactions.","## Keamanan Dimulai dari Opcode\n\nKeamanan smart contract bukan hanya tentang pola kode tingkat tinggi — ia berakar pada perilaku opcode EVM. Memahami bagaimana CALLER, ORIGIN, dan pola panggilan bekerja di tingkat bytecode adalah fondasi untuk menulis kontrak yang aman.\n\n## msg.sender vs tx.origin\n\nDua opcode EVM menyediakan informasi tentang siapa yang memulai eksekusi:\n\n- **CALLER** (msg.sender) — Alamat yang langsung memanggil kontrak saat ini. Dalam rantai panggilan A → B → C, msg.sender di C adalah B.\n- **ORIGIN** (tx.origin) — Alamat yang menandatangani transaksi asli. Dalam rantai A → B → C, tx.origin di C tetap A.\n\n```solidity\n\u002F\u002F JANGAN PERNAH gunakan tx.origin untuk autentikasi!\nfunction transfer(address to, uint256 amount) external {\n    \u002F\u002F BURUK: rentan terhadap phishing\n    require(tx.origin == owner);\n    \n    \u002F\u002F BAIK: hanya pemanggil langsung\n    require(msg.sender == owner);\n}\n```\n\nSerangan tx.origin: penyerang membuat kontrak berbahaya yang memanggil kontrak korban. Karena tx.origin adalah pengguna asli (yang berinteraksi dengan kontrak penyerang), pemeriksaan tx.origin berhasil dan penyerang mendapatkan akses.\n\n## Pola Kontrol Akses\n\n### Ownable Sederhana\n```solidity\naddress public owner;\n\nmodifier onlyOwner() {\n    require(msg.sender == owner, \"Not owner\");\n    _;\n}\n```\n\nDi tingkat EVM, modifier ini mengkompilasi menjadi: CALLER → SLOAD(owner_slot) → EQ → JUMPI ke revert atau lanjutkan.\n\n### Role-Based Access Control (RBAC)\n```solidity\nmapping(bytes32 => mapping(address => bool)) private _roles;\n\nbytes32 public constant ADMIN_ROLE = keccak256(\"ADMIN\");\nbytes32 public constant MINTER_ROLE = keccak256(\"MINTER\");\n\nfunction hasRole(bytes32 role, address account) public view returns (bool) {\n    return _roles[role][account];\n}\n```\n\nRBAC menggunakan mapping bersarang — di EVM, ini berarti double keccak256 hash untuk menghitung slot storage: `keccak256(account . keccak256(role . slot_dasar))`.\n\n## Serangan Reentrancy\n\nReentrancy adalah kerentanan paling terkenal dalam smart contract. Ia terjadi ketika kontrak memanggil kontrak eksternal sebelum memperbarui state internalnya.\n\n### Contoh Klasik\n```solidity\ncontract Vault {\n    mapping(address => uint256) public balances;\n    \n    function withdraw() external {\n        uint256 bal = balances[msg.sender];\n        \u002F\u002F BAHAYA: panggilan eksternal sebelum update state\n        (bool ok,) = msg.sender.call{value: bal}(\"\");\n        require(ok);\n        balances[msg.sender] = 0;  \u002F\u002F Terlambat!\n    }\n}\n```\n\nPenyerang bisa membuat kontrak dengan fungsi receive() yang memanggil withdraw() lagi. Karena balances[attacker] belum di-nolkan, pemeriksaan berhasil dan penyerang menarik dana berulang kali.\n\n### Di Tingkat EVM\nInilah yang terjadi secara sekuensial:\n1. SLOAD balances[attacker] → mengembalikan 1 ETH\n2. CALL dengan value=1 ETH ke attacker\n3. Kontrak attacker menerima 1 ETH, memanggil withdraw() lagi\n4. SLOAD balances[attacker] → MASIH 1 ETH (belum diupdate!)\n5. CALL lagi... dan seterusnya sampai vault kosong\n\n## Pola Checks-Effects-Interactions (CEI)\n\nPola pertahanan utama terhadap reentrancy:\n\n```solidity\nfunction withdraw() external {\n    \u002F\u002F CHECKS: validasi\n    uint256 bal = balances[msg.sender];\n    require(bal > 0, \"No balance\");\n    \n    \u002F\u002F EFFECTS: update state SEBELUM panggilan eksternal\n    balances[msg.sender] = 0;\n    \n    \u002F\u002F INTERACTIONS: panggilan eksternal terakhir\n    (bool ok,) = msg.sender.call{value: bal}(\"\");\n    require(ok);\n}\n```\n\nSekarang meskipun attacker masuk kembali, balances[attacker] sudah 0 dan withdraw() akan revert.\n\n## Mutex \u002F Reentrancy Guard\n\n```solidity\nuint256 private _locked = 1;\n\nmodifier nonReentrant() {\n    require(_locked == 1, \"Reentrancy\");\n    _locked = 2;\n    _;\n    _locked = 1;\n}\n```\n\nBiaya gas: 2 × SSTORE (warm) = ~5.800 gas overhead. Dengan EIP-1153 (transient storage), ini turun menjadi 2 × TSTORE = 200 gas.\n\n```solidity\n\u002F\u002F Dengan transient storage (EIP-1153):\nmodifier nonReentrant() {\n    assembly {\n        if tload(0) { revert(0, 0) }\n        tstore(0, 1)\n    }\n    _;\n    assembly {\n        tstore(0, 0)\n    }\n}\n```\n\n## Kerentanan Integer Overflow\n\nSebelum Solidity 0.8.0, operasi aritmatika bisa overflow tanpa peringatan:\n\n```solidity\n\u002F\u002F Solidity 0.7.x:\nuint8 x = 255;\nx += 1; \u002F\u002F x = 0 (overflow!)\n\n\u002F\u002F Solidity 0.8.0+:\nuint8 x = 255;\nx += 1; \u002F\u002F REVERT: overflow\n```\n\nDi tingkat EVM, Solidity 0.8+ menyisipkan pemeriksaan setelah setiap operasi aritmatika: DUP hasil → perbandingan → JUMPI ke revert. Ini menambah ~30 gas per operasi tetapi mencegah kerentanan kritis.\n\n## Flash Loan dan Manipulasi Harga\n\nFlash loan memungkinkan peminjaman tanpa jaminan dalam satu transaksi. Ini bisa digunakan untuk memanipulasi harga oracle:\n\n1. Pinjam 1 juta token via flash loan\n2. Jual di DEX untuk memindahkan harga\n3. Gunakan harga yang dimanipulasi untuk likuidasi\u002Farbitrase\n4. Kembalikan pinjaman + biaya\n\nPertahanan: gunakan Time-Weighted Average Price (TWAP) daripada harga spot, atau oracle off-chain seperti Chainlink.\n\n## DELEGATECALL dan Risiko Keamanan\n\nDELEGATECALL mengeksekusi kode kontrak lain dalam konteks storage pemanggil. Jika kontrak yang dipanggil berbahaya, ia bisa memodifikasi semua storage pemanggil.\n\n```solidity\n\u002F\u002F Proxy pattern: storage di proxy, logika di implementation\ncontract Proxy {\n    address public implementation;\n    \n    fallback() external payable {\n        \u002F\u002F DELEGATECALL ke implementation\n        (bool ok,) = implementation.delegatecall(msg.data);\n        require(ok);\n    }\n}\n```\n\nRisiko: jika implementation contract memiliki selfdestruct atau mengubah slot storage yang sama dengan proxy, hasilnya bisa katastrofis.\n\n## Praktik Terbaik Keamanan\n\n1. **Gunakan CEI pattern** — Selalu update state sebelum panggilan eksternal\n2. **Tambahkan reentrancy guard** — Untuk fungsi yang berinteraksi dengan kontrak lain\n3. **Jangan gunakan tx.origin** — Selalu gunakan msg.sender untuk autentikasi\n4. **Gunakan Solidity 0.8+** — Untuk overflow protection bawaan\n5. **Audit profesional** — Dapatkan audit sebelum deployment mainnet\n6. **Verifikasi formal** — Untuk kontrak yang menangani dana besar\n7. **Gunakan OpenZeppelin** — Library yang telah diaudit untuk pola umum\n\n## Kesimpulan\n\nKeamanan smart contract dimulai dari pemahaman mendalam tentang bagaimana EVM mengeksekusi kode. msg.sender, pola kontrol akses, pertahanan reentrancy, dan kesadaran akan vektor serangan — semuanya berakar pada perilaku opcode. Kontrak yang aman ditulis oleh pengembang yang berpikir di tingkat bytecode.","\u003Ch2 id=\"keamanan-dimulai-dari-opcode\">Keamanan Dimulai dari Opcode\u003C\u002Fh2>\n\u003Cp>Keamanan smart contract bukan hanya tentang pola kode tingkat tinggi — ia berakar pada perilaku opcode EVM. Memahami bagaimana CALLER, ORIGIN, dan pola panggilan bekerja di tingkat bytecode adalah fondasi untuk menulis kontrak yang aman.\u003C\u002Fp>\n\u003Ch2 id=\"msg-sender-vs-tx-origin\">msg.sender vs tx.origin\u003C\u002Fh2>\n\u003Cp>Dua opcode EVM menyediakan informasi tentang siapa yang memulai eksekusi:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>CALLER\u003C\u002Fstrong> (msg.sender) — Alamat yang langsung memanggil kontrak saat ini. Dalam rantai panggilan A → B → C, msg.sender di C adalah B.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>ORIGIN\u003C\u002Fstrong> (tx.origin) — Alamat yang menandatangani transaksi asli. Dalam rantai A → B → C, tx.origin di C tetap A.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F JANGAN PERNAH gunakan tx.origin untuk autentikasi!\nfunction transfer(address to, uint256 amount) external {\n    \u002F\u002F BURUK: rentan terhadap phishing\n    require(tx.origin == owner);\n    \n    \u002F\u002F BAIK: hanya pemanggil langsung\n    require(msg.sender == owner);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Serangan tx.origin: penyerang membuat kontrak berbahaya yang memanggil kontrak korban. Karena tx.origin adalah pengguna asli (yang berinteraksi dengan kontrak penyerang), pemeriksaan tx.origin berhasil dan penyerang mendapatkan akses.\u003C\u002Fp>\n\u003Ch2 id=\"pola-kontrol-akses\">Pola Kontrol Akses\u003C\u002Fh2>\n\u003Ch3>Ownable Sederhana\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-solidity\">address public owner;\n\nmodifier onlyOwner() {\n    require(msg.sender == owner, \"Not owner\");\n    _;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Di tingkat EVM, modifier ini mengkompilasi menjadi: CALLER → SLOAD(owner_slot) → EQ → JUMPI ke revert atau lanjutkan.\u003C\u002Fp>\n\u003Ch3>Role-Based Access Control (RBAC)\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-solidity\">mapping(bytes32 =&gt; mapping(address =&gt; bool)) private _roles;\n\nbytes32 public constant ADMIN_ROLE = keccak256(\"ADMIN\");\nbytes32 public constant MINTER_ROLE = keccak256(\"MINTER\");\n\nfunction hasRole(bytes32 role, address account) public view returns (bool) {\n    return _roles[role][account];\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>RBAC menggunakan mapping bersarang — di EVM, ini berarti double keccak256 hash untuk menghitung slot storage: \u003Ccode>keccak256(account . keccak256(role . slot_dasar))\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"serangan-reentrancy\">Serangan Reentrancy\u003C\u002Fh2>\n\u003Cp>Reentrancy adalah kerentanan paling terkenal dalam smart contract. Ia terjadi ketika kontrak memanggil kontrak eksternal sebelum memperbarui state internalnya.\u003C\u002Fp>\n\u003Ch3>Contoh Klasik\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-solidity\">contract Vault {\n    mapping(address =&gt; uint256) public balances;\n    \n    function withdraw() external {\n        uint256 bal = balances[msg.sender];\n        \u002F\u002F BAHAYA: panggilan eksternal sebelum update state\n        (bool ok,) = msg.sender.call{value: bal}(\"\");\n        require(ok);\n        balances[msg.sender] = 0;  \u002F\u002F Terlambat!\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Penyerang bisa membuat kontrak dengan fungsi receive() yang memanggil withdraw() lagi. Karena balances[attacker] belum di-nolkan, pemeriksaan berhasil dan penyerang menarik dana berulang kali.\u003C\u002Fp>\n\u003Ch3>Di Tingkat EVM\u003C\u002Fh3>\n\u003Cp>Inilah yang terjadi secara sekuensial:\u003C\u002Fp>\n\u003Col>\n\u003Cli>SLOAD balances[attacker] → mengembalikan 1 ETH\u003C\u002Fli>\n\u003Cli>CALL dengan value=1 ETH ke attacker\u003C\u002Fli>\n\u003Cli>Kontrak attacker menerima 1 ETH, memanggil withdraw() lagi\u003C\u002Fli>\n\u003Cli>SLOAD balances[attacker] → MASIH 1 ETH (belum diupdate!)\u003C\u002Fli>\n\u003Cli>CALL lagi… dan seterusnya sampai vault kosong\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"pola-checks-effects-interactions-cei\">Pola Checks-Effects-Interactions (CEI)\u003C\u002Fh2>\n\u003Cp>Pola pertahanan utama terhadap reentrancy:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function withdraw() external {\n    \u002F\u002F CHECKS: validasi\n    uint256 bal = balances[msg.sender];\n    require(bal &gt; 0, \"No balance\");\n    \n    \u002F\u002F EFFECTS: update state SEBELUM panggilan eksternal\n    balances[msg.sender] = 0;\n    \n    \u002F\u002F INTERACTIONS: panggilan eksternal terakhir\n    (bool ok,) = msg.sender.call{value: bal}(\"\");\n    require(ok);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Sekarang meskipun attacker masuk kembali, balances[attacker] sudah 0 dan withdraw() akan revert.\u003C\u002Fp>\n\u003Ch2 id=\"mutex-reentrancy-guard\">Mutex \u002F Reentrancy Guard\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-solidity\">uint256 private _locked = 1;\n\nmodifier nonReentrant() {\n    require(_locked == 1, \"Reentrancy\");\n    _locked = 2;\n    _;\n    _locked = 1;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Biaya gas: 2 × SSTORE (warm) = ~5.800 gas overhead. Dengan EIP-1153 (transient storage), ini turun menjadi 2 × TSTORE = 200 gas.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F Dengan transient storage (EIP-1153):\nmodifier nonReentrant() {\n    assembly {\n        if tload(0) { revert(0, 0) }\n        tstore(0, 1)\n    }\n    _;\n    assembly {\n        tstore(0, 0)\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"kerentanan-integer-overflow\">Kerentanan Integer Overflow\u003C\u002Fh2>\n\u003Cp>Sebelum Solidity 0.8.0, operasi aritmatika bisa overflow tanpa peringatan:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F Solidity 0.7.x:\nuint8 x = 255;\nx += 1; \u002F\u002F x = 0 (overflow!)\n\n\u002F\u002F Solidity 0.8.0+:\nuint8 x = 255;\nx += 1; \u002F\u002F REVERT: overflow\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Di tingkat EVM, Solidity 0.8+ menyisipkan pemeriksaan setelah setiap operasi aritmatika: DUP hasil → perbandingan → JUMPI ke revert. Ini menambah ~30 gas per operasi tetapi mencegah kerentanan kritis.\u003C\u002Fp>\n\u003Ch2 id=\"flash-loan-dan-manipulasi-harga\">Flash Loan dan Manipulasi Harga\u003C\u002Fh2>\n\u003Cp>Flash loan memungkinkan peminjaman tanpa jaminan dalam satu transaksi. Ini bisa digunakan untuk memanipulasi harga oracle:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Pinjam 1 juta token via flash loan\u003C\u002Fli>\n\u003Cli>Jual di DEX untuk memindahkan harga\u003C\u002Fli>\n\u003Cli>Gunakan harga yang dimanipulasi untuk likuidasi\u002Farbitrase\u003C\u002Fli>\n\u003Cli>Kembalikan pinjaman + biaya\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Pertahanan: gunakan Time-Weighted Average Price (TWAP) daripada harga spot, atau oracle off-chain seperti Chainlink.\u003C\u002Fp>\n\u003Ch2 id=\"delegatecall-dan-risiko-keamanan\">DELEGATECALL dan Risiko Keamanan\u003C\u002Fh2>\n\u003Cp>DELEGATECALL mengeksekusi kode kontrak lain dalam konteks storage pemanggil. Jika kontrak yang dipanggil berbahaya, ia bisa memodifikasi semua storage pemanggil.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F Proxy pattern: storage di proxy, logika di implementation\ncontract Proxy {\n    address public implementation;\n    \n    fallback() external payable {\n        \u002F\u002F DELEGATECALL ke implementation\n        (bool ok,) = implementation.delegatecall(msg.data);\n        require(ok);\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Risiko: jika implementation contract memiliki selfdestruct atau mengubah slot storage yang sama dengan proxy, hasilnya bisa katastrofis.\u003C\u002Fp>\n\u003Ch2 id=\"praktik-terbaik-keamanan\">Praktik Terbaik Keamanan\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>Gunakan CEI pattern\u003C\u002Fstrong> — Selalu update state sebelum panggilan eksternal\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tambahkan reentrancy guard\u003C\u002Fstrong> — Untuk fungsi yang berinteraksi dengan kontrak lain\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Jangan gunakan tx.origin\u003C\u002Fstrong> — Selalu gunakan msg.sender untuk autentikasi\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Gunakan Solidity 0.8+\u003C\u002Fstrong> — Untuk overflow protection bawaan\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Audit profesional\u003C\u002Fstrong> — Dapatkan audit sebelum deployment mainnet\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Verifikasi formal\u003C\u002Fstrong> — Untuk kontrak yang menangani dana besar\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Gunakan OpenZeppelin\u003C\u002Fstrong> — Library yang telah diaudit untuk pola umum\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"kesimpulan\">Kesimpulan\u003C\u002Fh2>\n\u003Cp>Keamanan smart contract dimulai dari pemahaman mendalam tentang bagaimana EVM mengeksekusi kode. msg.sender, pola kontrol akses, pertahanan reentrancy, dan kesadaran akan vektor serangan — semuanya berakar pada perilaku opcode. Kontrak yang aman ditulis oleh pengembang yang berpikir di tingkat bytecode.\u003C\u002Fp>\n","id","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:24.628207Z","Keamanan smart contract di EVM: msg.sender vs tx.origin, kontrol akses, serangan reentrancy, dan pola pertahanan CEI.","keamanan smart contract",null,"index, follow",[21,26,30],{"id":22,"name":23,"slug":24,"created_at":25},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":27,"name":28,"slug":29,"created_at":25},"c0000000-0000-0000-0000-000000000013","Security","security",{"id":31,"name":32,"slug":33,"created_at":25},"c0000000-0000-0000-0000-000000000014","Solidity","solidity","Blockchain",[36,42,48],{"id":37,"title":38,"slug":39,"excerpt":40,"locale":12,"category_name":34,"published_at":41},"d0000000-0000-0000-0000-000000000596","Lapisan Interoperabilitas Ethereum: Bagaimana 55+ L2 Menjadi Satu Chain","lapisan-interoperabilitas-ethereum-bagaimana-55-l2-menjadi-satu-chain","Ethereum memiliki 55+ rollup Layer 2, memecah likuiditas dan pengalaman pengguna. Lapisan Interoperabilitas Ethereum — menggabungkan pesan lintas-rollup, shared sequencer, dan based rollup — bertujuan menyatukan mereka menjadi satu jaringan yang dapat dikomposisi.","2026-03-28T10:44:44.364342Z",{"id":43,"title":44,"slug":45,"excerpt":46,"locale":12,"category_name":34,"published_at":47},"d0000000-0000-0000-0000-000000000595","ZK Proofs Melampaui Rollups: Inferensi AI Terverifikasi di Ethereum","zk-proofs-melampaui-rollups-inferensi-ai-terverifikasi-ethereum","Zero-knowledge proofs bukan lagi sekadar alat penskalaan. Pada 2026, zkML memungkinkan inferensi AI terverifikasi on-chain, ZK coprocessor memindahkan komputasi berat off-chain dengan verifikasi on-chain, dan sistem pembuktian baru seperti SP1 dan Jolt menjadikannya praktis.","2026-03-28T10:44:44.358370Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":34,"published_at":53},"d0000000-0000-0000-0000-000000000572","EIP-7702 dalam Praktik: Membangun Alur Akun Pintar Setelah Pectra","eip-7702-dalam-praktik-membangun-alur-akun-pintar-setelah-pectra","EIP-7702 memungkinkan EOA Ethereum mana pun untuk sementara bertindak sebagai kontrak pintar dalam satu transaksi. Berikut cara mengimplementasikan transaksi batch, sponsorship gas, dan social recovery menggunakan primitif account abstraction baru.","2026-03-28T10:44:42.816894Z",{"id":13,"name":55,"slug":56,"bio":57,"photo_url":18,"linkedin":18,"role":58,"created_at":59,"updated_at":59},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]