[{"data":1,"prerenderedAt":1134},["ShallowReactive",2],{"tidbit-agent-secrets-bitwarden":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"body":11,"_type":1128,"_id":1129,"_source":1130,"_file":1131,"_stem":1132,"_extension":1133},"/tidbits/agent-secrets-bitwarden","tidbits",false,"","Giving Agents Secrets Without a .env","A plaintext ~/.env is the easiest thing for a coding agent to read and the hardest to take back. Here's how I keep agent secrets in Bitwarden instead, with a scoped, lockable way to use them.","2026-10-17",{"type":12,"children":13,"toc":1126},"root",[14,31,36,45,74,204,256,264,277,366,378,697,716,724,737,914,924,932,952,1060,1068,1088,1108,1120],{"type":15,"tag":16,"props":17,"children":18},"element","p",{},[19,22,29],{"type":20,"value":21},"text","The path of least resistance for giving coding agents API keys is a ",{"type":15,"tag":23,"props":24,"children":26},"code",{"className":25},[],[27],{"type":20,"value":28},".env",{"type":20,"value":30}," file in your home directory. It works. It's also a plaintext file that any process on the machine can read, sitting in every backup, with no way to say \"not right now\".",{"type":15,"tag":16,"props":32,"children":33},{},[34],{"type":20,"value":35},"I keep agent secrets in Bitwarden (self-hosted Vaultwarden, in my case) with a small wrapper in front of it.",{"type":15,"tag":16,"props":37,"children":38},{},[39],{"type":15,"tag":40,"props":41,"children":42},"strong",{},[43],{"type":20,"value":44},"Store: one secure note, one hidden field per variable",{"type":15,"tag":16,"props":46,"children":47},{},[48,50,56,58,64,66,72],{"type":20,"value":49},"Rather than one vault item per key, I use a single secure note called ",{"type":15,"tag":23,"props":51,"children":53},{"className":52},[],[54],{"type":20,"value":55},"agent-env",{"type":20,"value":57}," with a hidden custom field for each variable. One ",{"type":15,"tag":23,"props":59,"children":61},{"className":60},[],[62],{"type":20,"value":63},"bw get item",{"type":20,"value":65}," call fetches the lot, which matters because the ",{"type":15,"tag":23,"props":67,"children":69},{"className":68},[],[70],{"type":20,"value":71},"bw",{"type":20,"value":73}," CLI isn't fast. Adding a secret is just adding a field in the web vault.",{"type":15,"tag":75,"props":76,"children":80},"pre",{"className":77,"code":78,"language":79,"meta":7,"style":7},"language-bash shiki shiki-themes github-light","bw get template item | jq --argjson f \"$fields\" '\n  .type = 2 | .secureNote = {type: 0} | .login = null\n  | .name = \"agent-env\" | .fields = $f' | bw encode | bw create item\n","bash",[81],{"type":15,"tag":23,"props":82,"children":83},{"__ignoreMap":7},[84,154,163],{"type":15,"tag":85,"props":86,"children":89},"span",{"class":87,"line":88},"line",1,[90,95,101,106,111,117,122,128,133,138,144,149],{"type":15,"tag":85,"props":91,"children":93},{"style":92},"--shiki-default:#6F42C1",[94],{"type":20,"value":71},{"type":15,"tag":85,"props":96,"children":98},{"style":97},"--shiki-default:#032F62",[99],{"type":20,"value":100}," get",{"type":15,"tag":85,"props":102,"children":103},{"style":97},[104],{"type":20,"value":105}," template",{"type":15,"tag":85,"props":107,"children":108},{"style":97},[109],{"type":20,"value":110}," item",{"type":15,"tag":85,"props":112,"children":114},{"style":113},"--shiki-default:#D73A49",[115],{"type":20,"value":116}," |",{"type":15,"tag":85,"props":118,"children":119},{"style":92},[120],{"type":20,"value":121}," jq",{"type":15,"tag":85,"props":123,"children":125},{"style":124},"--shiki-default:#005CC5",[126],{"type":20,"value":127}," --argjson",{"type":15,"tag":85,"props":129,"children":130},{"style":97},[131],{"type":20,"value":132}," f",{"type":15,"tag":85,"props":134,"children":135},{"style":97},[136],{"type":20,"value":137}," \"",{"type":15,"tag":85,"props":139,"children":141},{"style":140},"--shiki-default:#24292E",[142],{"type":20,"value":143},"$fields",{"type":15,"tag":85,"props":145,"children":146},{"style":97},[147],{"type":20,"value":148},"\"",{"type":15,"tag":85,"props":150,"children":151},{"style":97},[152],{"type":20,"value":153}," '\n",{"type":15,"tag":85,"props":155,"children":157},{"class":87,"line":156},2,[158],{"type":15,"tag":85,"props":159,"children":160},{"style":97},[161],{"type":20,"value":162},"  .type = 2 | .secureNote = {type: 0} | .login = null\n",{"type":15,"tag":85,"props":164,"children":166},{"class":87,"line":165},3,[167,172,176,181,186,190,194,199],{"type":15,"tag":85,"props":168,"children":169},{"style":97},[170],{"type":20,"value":171},"  | .name = \"agent-env\" | .fields = $f'",{"type":15,"tag":85,"props":173,"children":174},{"style":113},[175],{"type":20,"value":116},{"type":15,"tag":85,"props":177,"children":178},{"style":92},[179],{"type":20,"value":180}," bw",{"type":15,"tag":85,"props":182,"children":183},{"style":97},[184],{"type":20,"value":185}," encode",{"type":15,"tag":85,"props":187,"children":188},{"style":113},[189],{"type":20,"value":116},{"type":15,"tag":85,"props":191,"children":192},{"style":92},[193],{"type":20,"value":180},{"type":15,"tag":85,"props":195,"children":196},{"style":97},[197],{"type":20,"value":198}," create",{"type":15,"tag":85,"props":200,"children":201},{"style":97},[202],{"type":20,"value":203}," item\n",{"type":15,"tag":16,"props":205,"children":206},{},[207,209,214,216,222,224,230,232,238,240,246,248,254],{"type":20,"value":208},"Where ",{"type":15,"tag":23,"props":210,"children":212},{"className":211},[],[213],{"type":20,"value":143},{"type":20,"value":215}," is your variables as ",{"type":15,"tag":23,"props":217,"children":219},{"className":218},[],[220],{"type":20,"value":221},"[{name, value, type: 1}]",{"type":20,"value":223}," (type ",{"type":15,"tag":23,"props":225,"children":227},{"className":226},[],[228],{"type":20,"value":229},"1",{"type":20,"value":231}," is a hidden field). Verify the round trip by comparing values in ",{"type":15,"tag":23,"props":233,"children":235},{"className":234},[],[236],{"type":20,"value":237},"jq",{"type":20,"value":239}," and printing only ",{"type":15,"tag":23,"props":241,"children":243},{"className":242},[],[244],{"type":20,"value":245},"ok",{"type":20,"value":247},"/",{"type":15,"tag":23,"props":249,"children":251},{"className":250},[],[252],{"type":20,"value":253},"MISMATCH",{"type":20,"value":255},", so the secrets never hit your terminal.",{"type":15,"tag":16,"props":257,"children":258},{},[259],{"type":15,"tag":40,"props":260,"children":261},{},[262],{"type":20,"value":263},"Use: inject into one command, never print",{"type":15,"tag":16,"props":265,"children":266},{},[267,269,275],{"type":20,"value":268},"Agents don't read secrets. They run commands ",{"type":15,"tag":270,"props":271,"children":272},"em",{},[273],{"type":20,"value":274},"with",{"type":20,"value":276}," them:",{"type":15,"tag":75,"props":278,"children":280},{"className":77,"code":279,"language":79,"meta":7,"style":7},"withsecrets OPENAI_API_KEY -- python summarise.py   # just the one it needs\nwithsecrets -- npm run deploy                        # everything\nwithsecrets --list                                   # names only\n",[281],{"type":15,"tag":23,"props":282,"children":283},{"__ignoreMap":7},[284,318,349],{"type":15,"tag":85,"props":285,"children":286},{"class":87,"line":88},[287,292,297,302,307,312],{"type":15,"tag":85,"props":288,"children":289},{"style":92},[290],{"type":20,"value":291},"withsecrets",{"type":15,"tag":85,"props":293,"children":294},{"style":97},[295],{"type":20,"value":296}," OPENAI_API_KEY",{"type":15,"tag":85,"props":298,"children":299},{"style":124},[300],{"type":20,"value":301}," --",{"type":15,"tag":85,"props":303,"children":304},{"style":97},[305],{"type":20,"value":306}," python",{"type":15,"tag":85,"props":308,"children":309},{"style":97},[310],{"type":20,"value":311}," summarise.py",{"type":15,"tag":85,"props":313,"children":315},{"style":314},"--shiki-default:#6A737D",[316],{"type":20,"value":317},"   # just the one it needs\n",{"type":15,"tag":85,"props":319,"children":320},{"class":87,"line":156},[321,325,329,334,339,344],{"type":15,"tag":85,"props":322,"children":323},{"style":92},[324],{"type":20,"value":291},{"type":15,"tag":85,"props":326,"children":327},{"style":124},[328],{"type":20,"value":301},{"type":15,"tag":85,"props":330,"children":331},{"style":97},[332],{"type":20,"value":333}," npm",{"type":15,"tag":85,"props":335,"children":336},{"style":97},[337],{"type":20,"value":338}," run",{"type":15,"tag":85,"props":340,"children":341},{"style":97},[342],{"type":20,"value":343}," deploy",{"type":15,"tag":85,"props":345,"children":346},{"style":314},[347],{"type":20,"value":348},"                        # everything\n",{"type":15,"tag":85,"props":350,"children":351},{"class":87,"line":165},[352,356,361],{"type":15,"tag":85,"props":353,"children":354},{"style":92},[355],{"type":20,"value":291},{"type":15,"tag":85,"props":357,"children":358},{"style":124},[359],{"type":20,"value":360}," --list",{"type":15,"tag":85,"props":362,"children":363},{"style":314},[364],{"type":20,"value":365},"                                   # names only\n",{"type":15,"tag":16,"props":367,"children":368},{},[369,371,376],{"type":20,"value":370},"The core of ",{"type":15,"tag":23,"props":372,"children":374},{"className":373},[],[375],{"type":20,"value":291},{"type":20,"value":377}," is short:",{"type":15,"tag":75,"props":379,"children":381},{"className":77,"code":380,"language":79,"meta":7,"style":7},"json=$(bw get item agent-env --nointeraction)\nunset BW_SESSION   # the child never gets vault access\n\nwhile IFS= read -r -d '' k && IFS= read -r -d '' v; do\n  export \"$k=$v\"\ndone \u003C \u003C(jq -j --args '.fields[]\n  | select(($ARGS.positional|length)==0 or (.name as $n | $ARGS.positional|index($n)))\n  | .name, \"\\u0000\", .value, \"\\u0000\"' \"${vars[@]}\" \u003C\u003C\u003C\"$json\")\n\nexec \"$@\"\n",[382],{"type":15,"tag":23,"props":383,"children":384},{"__ignoreMap":7},[385,430,448,457,540,572,610,619,667,675],{"type":15,"tag":85,"props":386,"children":387},{"class":87,"line":88},[388,393,398,403,407,411,415,420,425],{"type":15,"tag":85,"props":389,"children":390},{"style":140},[391],{"type":20,"value":392},"json",{"type":15,"tag":85,"props":394,"children":395},{"style":113},[396],{"type":20,"value":397},"=",{"type":15,"tag":85,"props":399,"children":400},{"style":140},[401],{"type":20,"value":402},"$(",{"type":15,"tag":85,"props":404,"children":405},{"style":92},[406],{"type":20,"value":71},{"type":15,"tag":85,"props":408,"children":409},{"style":97},[410],{"type":20,"value":100},{"type":15,"tag":85,"props":412,"children":413},{"style":97},[414],{"type":20,"value":110},{"type":15,"tag":85,"props":416,"children":417},{"style":97},[418],{"type":20,"value":419}," agent-env",{"type":15,"tag":85,"props":421,"children":422},{"style":124},[423],{"type":20,"value":424}," --nointeraction",{"type":15,"tag":85,"props":426,"children":427},{"style":140},[428],{"type":20,"value":429},")\n",{"type":15,"tag":85,"props":431,"children":432},{"class":87,"line":156},[433,438,443],{"type":15,"tag":85,"props":434,"children":435},{"style":124},[436],{"type":20,"value":437},"unset",{"type":15,"tag":85,"props":439,"children":440},{"style":97},[441],{"type":20,"value":442}," BW_SESSION",{"type":15,"tag":85,"props":444,"children":445},{"style":314},[446],{"type":20,"value":447},"   # the child never gets vault access\n",{"type":15,"tag":85,"props":449,"children":450},{"class":87,"line":165},[451],{"type":15,"tag":85,"props":452,"children":454},{"emptyLinePlaceholder":453},true,[455],{"type":20,"value":456},"\n",{"type":15,"tag":85,"props":458,"children":460},{"class":87,"line":459},4,[461,466,471,475,480,485,490,495,500,505,509,513,517,521,525,530,535],{"type":15,"tag":85,"props":462,"children":463},{"style":113},[464],{"type":20,"value":465},"while",{"type":15,"tag":85,"props":467,"children":468},{"style":140},[469],{"type":20,"value":470}," IFS",{"type":15,"tag":85,"props":472,"children":473},{"style":113},[474],{"type":20,"value":397},{"type":15,"tag":85,"props":476,"children":477},{"style":124},[478],{"type":20,"value":479}," read",{"type":15,"tag":85,"props":481,"children":482},{"style":124},[483],{"type":20,"value":484}," -r",{"type":15,"tag":85,"props":486,"children":487},{"style":124},[488],{"type":20,"value":489}," -d",{"type":15,"tag":85,"props":491,"children":492},{"style":97},[493],{"type":20,"value":494}," ''",{"type":15,"tag":85,"props":496,"children":497},{"style":97},[498],{"type":20,"value":499}," k",{"type":15,"tag":85,"props":501,"children":502},{"style":140},[503],{"type":20,"value":504}," && IFS",{"type":15,"tag":85,"props":506,"children":507},{"style":113},[508],{"type":20,"value":397},{"type":15,"tag":85,"props":510,"children":511},{"style":124},[512],{"type":20,"value":479},{"type":15,"tag":85,"props":514,"children":515},{"style":124},[516],{"type":20,"value":484},{"type":15,"tag":85,"props":518,"children":519},{"style":124},[520],{"type":20,"value":489},{"type":15,"tag":85,"props":522,"children":523},{"style":97},[524],{"type":20,"value":494},{"type":15,"tag":85,"props":526,"children":527},{"style":97},[528],{"type":20,"value":529}," v",{"type":15,"tag":85,"props":531,"children":532},{"style":140},[533],{"type":20,"value":534},"; ",{"type":15,"tag":85,"props":536,"children":537},{"style":113},[538],{"type":20,"value":539},"do\n",{"type":15,"tag":85,"props":541,"children":543},{"class":87,"line":542},5,[544,549,553,558,562,567],{"type":15,"tag":85,"props":545,"children":546},{"style":113},[547],{"type":20,"value":548},"  export",{"type":15,"tag":85,"props":550,"children":551},{"style":97},[552],{"type":20,"value":137},{"type":15,"tag":85,"props":554,"children":555},{"style":140},[556],{"type":20,"value":557},"$k",{"type":15,"tag":85,"props":559,"children":560},{"style":97},[561],{"type":20,"value":397},{"type":15,"tag":85,"props":563,"children":564},{"style":140},[565],{"type":20,"value":566},"$v",{"type":15,"tag":85,"props":568,"children":569},{"style":97},[570],{"type":20,"value":571},"\"\n",{"type":15,"tag":85,"props":573,"children":575},{"class":87,"line":574},6,[576,581,586,591,595,600,605],{"type":15,"tag":85,"props":577,"children":578},{"style":113},[579],{"type":20,"value":580},"done",{"type":15,"tag":85,"props":582,"children":583},{"style":113},[584],{"type":20,"value":585}," \u003C",{"type":15,"tag":85,"props":587,"children":588},{"style":97},[589],{"type":20,"value":590}," \u003C(",{"type":15,"tag":85,"props":592,"children":593},{"style":92},[594],{"type":20,"value":237},{"type":15,"tag":85,"props":596,"children":597},{"style":124},[598],{"type":20,"value":599}," -j",{"type":15,"tag":85,"props":601,"children":602},{"style":124},[603],{"type":20,"value":604}," --args",{"type":15,"tag":85,"props":606,"children":607},{"style":97},[608],{"type":20,"value":609}," '.fields[]\n",{"type":15,"tag":85,"props":611,"children":613},{"class":87,"line":612},7,[614],{"type":15,"tag":85,"props":615,"children":616},{"style":97},[617],{"type":20,"value":618},"  | select(($ARGS.positional|length)==0 or (.name as $n | $ARGS.positional|index($n)))\n",{"type":15,"tag":85,"props":620,"children":622},{"class":87,"line":621},8,[623,628,633,638,643,648,653,657,662],{"type":15,"tag":85,"props":624,"children":625},{"style":97},[626],{"type":20,"value":627},"  | .name, \"\\u0000\", .value, \"\\u0000\"' \"${",{"type":15,"tag":85,"props":629,"children":630},{"style":140},[631],{"type":20,"value":632},"vars",{"type":15,"tag":85,"props":634,"children":635},{"style":97},[636],{"type":20,"value":637},"[",{"type":15,"tag":85,"props":639,"children":640},{"style":113},[641],{"type":20,"value":642},"@",{"type":15,"tag":85,"props":644,"children":645},{"style":97},[646],{"type":20,"value":647},"]}\" ",{"type":15,"tag":85,"props":649,"children":650},{"style":113},[651],{"type":20,"value":652},"\u003C\u003C\u003C",{"type":15,"tag":85,"props":654,"children":655},{"style":97},[656],{"type":20,"value":148},{"type":15,"tag":85,"props":658,"children":659},{"style":140},[660],{"type":20,"value":661},"$json",{"type":15,"tag":85,"props":663,"children":664},{"style":97},[665],{"type":20,"value":666},"\")\n",{"type":15,"tag":85,"props":668,"children":670},{"class":87,"line":669},9,[671],{"type":15,"tag":85,"props":672,"children":673},{"emptyLinePlaceholder":453},[674],{"type":20,"value":456},{"type":15,"tag":85,"props":676,"children":678},{"class":87,"line":677},10,[679,684,688,693],{"type":15,"tag":85,"props":680,"children":681},{"style":124},[682],{"type":20,"value":683},"exec",{"type":15,"tag":85,"props":685,"children":686},{"style":97},[687],{"type":20,"value":137},{"type":15,"tag":85,"props":689,"children":690},{"style":124},[691],{"type":20,"value":692},"$@",{"type":15,"tag":85,"props":694,"children":695},{"style":97},[696],{"type":20,"value":571},{"type":15,"tag":16,"props":698,"children":699},{},[700,702,707,709,714],{"type":20,"value":701},"NUL-separated output means values with spaces, quotes or ",{"type":15,"tag":23,"props":703,"children":705},{"className":704},[],[706],{"type":20,"value":397},{"type":20,"value":708}," survive intact, and ",{"type":15,"tag":23,"props":710,"children":712},{"className":711},[],[713],{"type":20,"value":683},{"type":20,"value":715}," means the secrets only live in that one process's environment, not in the agent's transcript.",{"type":15,"tag":16,"props":717,"children":718},{},[719],{"type":15,"tag":40,"props":720,"children":721},{},[722],{"type":20,"value":723},"Access: I hold the lock",{"type":15,"tag":16,"props":725,"children":726},{},[727,729,735],{"type":20,"value":728},"The vault session key is what makes ",{"type":15,"tag":23,"props":730,"children":732},{"className":731},[],[733],{"type":20,"value":734},"bw get",{"type":20,"value":736}," work. I park it in the macOS Keychain with two tiny scripts:",{"type":15,"tag":75,"props":738,"children":740},{"className":77,"code":739,"language":79,"meta":7,"style":7},"# bw-agent-unlock — I run this, agents don't\nsession=$(bw unlock --raw)\nsecurity add-generic-password -U -a \"$USER\" -s bw-agent-session -w \"$session\"\n\n# bw-agent-lock — revoke everything\nbw lock\nsecurity delete-generic-password -a \"$USER\" -s bw-agent-session\n",[741],{"type":15,"tag":23,"props":742,"children":743},{"__ignoreMap":7},[744,752,786,850,857,865,877],{"type":15,"tag":85,"props":745,"children":746},{"class":87,"line":88},[747],{"type":15,"tag":85,"props":748,"children":749},{"style":314},[750],{"type":20,"value":751},"# bw-agent-unlock — I run this, agents don't\n",{"type":15,"tag":85,"props":753,"children":754},{"class":87,"line":156},[755,760,764,768,772,777,782],{"type":15,"tag":85,"props":756,"children":757},{"style":140},[758],{"type":20,"value":759},"session",{"type":15,"tag":85,"props":761,"children":762},{"style":113},[763],{"type":20,"value":397},{"type":15,"tag":85,"props":765,"children":766},{"style":140},[767],{"type":20,"value":402},{"type":15,"tag":85,"props":769,"children":770},{"style":92},[771],{"type":20,"value":71},{"type":15,"tag":85,"props":773,"children":774},{"style":97},[775],{"type":20,"value":776}," unlock",{"type":15,"tag":85,"props":778,"children":779},{"style":124},[780],{"type":20,"value":781}," --raw",{"type":15,"tag":85,"props":783,"children":784},{"style":140},[785],{"type":20,"value":429},{"type":15,"tag":85,"props":787,"children":788},{"class":87,"line":165},[789,794,799,804,809,813,818,822,827,832,837,841,846],{"type":15,"tag":85,"props":790,"children":791},{"style":92},[792],{"type":20,"value":793},"security",{"type":15,"tag":85,"props":795,"children":796},{"style":97},[797],{"type":20,"value":798}," add-generic-password",{"type":15,"tag":85,"props":800,"children":801},{"style":124},[802],{"type":20,"value":803}," -U",{"type":15,"tag":85,"props":805,"children":806},{"style":124},[807],{"type":20,"value":808}," -a",{"type":15,"tag":85,"props":810,"children":811},{"style":97},[812],{"type":20,"value":137},{"type":15,"tag":85,"props":814,"children":815},{"style":140},[816],{"type":20,"value":817},"$USER",{"type":15,"tag":85,"props":819,"children":820},{"style":97},[821],{"type":20,"value":148},{"type":15,"tag":85,"props":823,"children":824},{"style":124},[825],{"type":20,"value":826}," -s",{"type":15,"tag":85,"props":828,"children":829},{"style":97},[830],{"type":20,"value":831}," bw-agent-session",{"type":15,"tag":85,"props":833,"children":834},{"style":124},[835],{"type":20,"value":836}," -w",{"type":15,"tag":85,"props":838,"children":839},{"style":97},[840],{"type":20,"value":137},{"type":15,"tag":85,"props":842,"children":843},{"style":140},[844],{"type":20,"value":845},"$session",{"type":15,"tag":85,"props":847,"children":848},{"style":97},[849],{"type":20,"value":571},{"type":15,"tag":85,"props":851,"children":852},{"class":87,"line":459},[853],{"type":15,"tag":85,"props":854,"children":855},{"emptyLinePlaceholder":453},[856],{"type":20,"value":456},{"type":15,"tag":85,"props":858,"children":859},{"class":87,"line":542},[860],{"type":15,"tag":85,"props":861,"children":862},{"style":314},[863],{"type":20,"value":864},"# bw-agent-lock — revoke everything\n",{"type":15,"tag":85,"props":866,"children":867},{"class":87,"line":574},[868,872],{"type":15,"tag":85,"props":869,"children":870},{"style":92},[871],{"type":20,"value":71},{"type":15,"tag":85,"props":873,"children":874},{"style":97},[875],{"type":20,"value":876}," lock\n",{"type":15,"tag":85,"props":878,"children":879},{"class":87,"line":612},[880,884,889,893,897,901,905,909],{"type":15,"tag":85,"props":881,"children":882},{"style":92},[883],{"type":20,"value":793},{"type":15,"tag":85,"props":885,"children":886},{"style":97},[887],{"type":20,"value":888}," delete-generic-password",{"type":15,"tag":85,"props":890,"children":891},{"style":124},[892],{"type":20,"value":808},{"type":15,"tag":85,"props":894,"children":895},{"style":97},[896],{"type":20,"value":137},{"type":15,"tag":85,"props":898,"children":899},{"style":140},[900],{"type":20,"value":817},{"type":15,"tag":85,"props":902,"children":903},{"style":97},[904],{"type":20,"value":148},{"type":15,"tag":85,"props":906,"children":907},{"style":124},[908],{"type":20,"value":826},{"type":15,"tag":85,"props":910,"children":911},{"style":97},[912],{"type":20,"value":913}," bw-agent-session\n",{"type":15,"tag":16,"props":915,"children":916},{},[917,922],{"type":15,"tag":23,"props":918,"children":920},{"className":919},[],[921],{"type":20,"value":291},{"type":20,"value":923}," reads the key from Keychain. When I lock, it fails with \"ask the user to unlock\", and the agent stops and asks me. Unlocking needs my master password, so an agent can't do it for itself.",{"type":15,"tag":16,"props":925,"children":926},{},[927],{"type":15,"tag":40,"props":928,"children":929},{},[930],{"type":20,"value":931},"Guardrails: make the wrapper the only door",{"type":15,"tag":16,"props":933,"children":934},{},[935,937,943,945,950],{"type":20,"value":936},"In Claude Code's ",{"type":15,"tag":23,"props":938,"children":940},{"className":939},[],[941],{"type":20,"value":942},"~/.claude/settings.json",{"type":20,"value":944}," I deny the direct routes, so agents have to go through ",{"type":15,"tag":23,"props":946,"children":948},{"className":947},[],[949],{"type":20,"value":291},{"type":20,"value":951},":",{"type":15,"tag":75,"props":953,"children":956},{"className":954,"code":955,"language":392,"meta":7,"style":7},"language-json shiki shiki-themes github-light","\"permissions\": {\n  \"deny\": [\n    \"Bash(bw get:*)\", \"Bash(bw list:*)\", \"Bash(bw export:*)\", \"Bash(bw unlock:*)\",\n    \"Bash(security find-generic-password:*)\", \"Read(~/.env)\"\n  ]\n}\n",[957],{"type":15,"tag":23,"props":958,"children":959},{"__ignoreMap":7},[960,973,986,1027,1044,1052],{"type":15,"tag":85,"props":961,"children":962},{"class":87,"line":88},[963,968],{"type":15,"tag":85,"props":964,"children":965},{"style":97},[966],{"type":20,"value":967},"\"permissions\"",{"type":15,"tag":85,"props":969,"children":970},{"style":140},[971],{"type":20,"value":972},": {\n",{"type":15,"tag":85,"props":974,"children":975},{"class":87,"line":156},[976,981],{"type":15,"tag":85,"props":977,"children":978},{"style":124},[979],{"type":20,"value":980},"  \"deny\"",{"type":15,"tag":85,"props":982,"children":983},{"style":140},[984],{"type":20,"value":985},": [\n",{"type":15,"tag":85,"props":987,"children":988},{"class":87,"line":165},[989,994,999,1004,1008,1013,1017,1022],{"type":15,"tag":85,"props":990,"children":991},{"style":97},[992],{"type":20,"value":993},"    \"Bash(bw get:*)\"",{"type":15,"tag":85,"props":995,"children":996},{"style":140},[997],{"type":20,"value":998},", ",{"type":15,"tag":85,"props":1000,"children":1001},{"style":97},[1002],{"type":20,"value":1003},"\"Bash(bw list:*)\"",{"type":15,"tag":85,"props":1005,"children":1006},{"style":140},[1007],{"type":20,"value":998},{"type":15,"tag":85,"props":1009,"children":1010},{"style":97},[1011],{"type":20,"value":1012},"\"Bash(bw export:*)\"",{"type":15,"tag":85,"props":1014,"children":1015},{"style":140},[1016],{"type":20,"value":998},{"type":15,"tag":85,"props":1018,"children":1019},{"style":97},[1020],{"type":20,"value":1021},"\"Bash(bw unlock:*)\"",{"type":15,"tag":85,"props":1023,"children":1024},{"style":140},[1025],{"type":20,"value":1026},",\n",{"type":15,"tag":85,"props":1028,"children":1029},{"class":87,"line":459},[1030,1035,1039],{"type":15,"tag":85,"props":1031,"children":1032},{"style":97},[1033],{"type":20,"value":1034},"    \"Bash(security find-generic-password:*)\"",{"type":15,"tag":85,"props":1036,"children":1037},{"style":140},[1038],{"type":20,"value":998},{"type":15,"tag":85,"props":1040,"children":1041},{"style":97},[1042],{"type":20,"value":1043},"\"Read(~/.env)\"\n",{"type":15,"tag":85,"props":1045,"children":1046},{"class":87,"line":542},[1047],{"type":15,"tag":85,"props":1048,"children":1049},{"style":140},[1050],{"type":20,"value":1051},"  ]\n",{"type":15,"tag":85,"props":1053,"children":1054},{"class":87,"line":574},[1055],{"type":15,"tag":85,"props":1056,"children":1057},{"style":140},[1058],{"type":20,"value":1059},"}\n",{"type":15,"tag":16,"props":1061,"children":1062},{},[1063],{"type":15,"tag":40,"props":1064,"children":1065},{},[1066],{"type":20,"value":1067},"What this doesn't do",{"type":15,"tag":16,"props":1069,"children":1070},{},[1071,1073,1079,1081,1086],{"type":20,"value":1072},"An agent that can run arbitrary commands could still run ",{"type":15,"tag":23,"props":1074,"children":1076},{"className":1075},[],[1077],{"type":20,"value":1078},"withsecrets -- env",{"type":20,"value":1080},". If a process can use a secret, a determined agent can see it. What you ",{"type":15,"tag":270,"props":1082,"children":1083},{},[1084],{"type":20,"value":1085},"do",{"type":20,"value":1087}," get is no plaintext at rest, least-privilege by default, and an off switch.",{"type":15,"tag":16,"props":1089,"children":1090},{},[1091,1093,1098,1100,1106],{"type":20,"value":1092},"The other catch: a Bitwarden session key unlocks the ",{"type":15,"tag":270,"props":1094,"children":1095},{},[1096],{"type":20,"value":1097},"whole",{"type":20,"value":1099}," vault, not just one note. Lock it when you're not working. Or, better, put agent secrets in a separate account and point the CLI at it with ",{"type":15,"tag":23,"props":1101,"children":1103},{"className":1102},[],[1104],{"type":20,"value":1105},"BITWARDENCLI_APPDATA_DIR",{"type":20,"value":1107},", so a leaked session exposes those keys and nothing else.",{"type":15,"tag":16,"props":1109,"children":1110},{},[1111,1113,1118],{"type":20,"value":1112},"If you're moving keys out of a ",{"type":15,"tag":23,"props":1114,"children":1116},{"className":1115},[],[1117],{"type":20,"value":28},{"type":20,"value":1119},", rotate anything you care about afterwards. Deleting the file doesn't delete it from your backups.",{"type":15,"tag":1121,"props":1122,"children":1123},"style",{},[1124],{"type":20,"value":1125},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":156,"depth":156,"links":1127},[],"markdown","content:tidbits:agent-secrets-bitwarden.md","content","tidbits/agent-secrets-bitwarden.md","tidbits/agent-secrets-bitwarden","md",1792253687674]