XLSM File Documentation


Summary

An XLSM (Excel Open XML Macro-Enabled Spreadsheet) file is a Microsoft Excel workbook that, unlike the ordinary .xlsx, can contain VBA macros — automation code stored in the package. It is a ZIP-based Office Open XML file (MIME application/vnd.ms-excel.sheet.macroEnabled.12). Excel, LibreOffice Calc, and WPS open it; Google Sheets and Excel for the web show the data but do not run the macros. The catch is safety: only enable macros in an .xlsm from a source you trust.

Technical details

FeatureValue
Full nameMicrosoft Excel Macro-Enabled Workbook (Open XML)
File extension.xlsm
MIME typeapplication/vnd.ms-excel.sheet.macroEnabled.12
Format typeZIP-based Office Open XML (OPC) package with a VBA project
DeveloperMicrosoft
Introduced2007 (Excel 2007)
StandardECMA-376 / ISO-IEC 29500 (Office Open XML)
Open standardPartial — documented, Microsoft-controlled
Container / baseZIP archive (Open Packaging Conventions)
Magic number50 4B 03 04 (“PK” ZIP local file header) at offset 0
Macro partxl/vbaProject.bin (present in XLSM, absent in XLSX)
Macro languageVBA (Visual Basic for Applications)
Content type flag[Content_Types].xml declares macroEnabled.12
EncodingUTF-8 XML parts inside the ZIP
Max rows / columns1,048,576 rows × 16,384 columns
Security riskHigh — VBA macros can execute code
Related extensions.xlsx, .xlsb, .xls, .xltm, .ods, .csv
Opens inMicrosoft Excel, LibreOffice Calc, WPS, OnlyOffice
Specificationlearn.microsoft.com (MS-XLSX / OOXML)
File signature (magic bytes)
50 4B 03 04

Offset 0, 4 bytes. An XLSM is a ZIP archive, so it starts with the ZIP local-file-header signature 50 4B 03 04 (ASCII PK) — byte-identical to .xlsx, .docx, and any ZIP. The header alone cannot tell XLSM from XLSX. The difference is inside: an XLSM contains an xl/vbaProject.bin part, and its [Content_Types].xml declares the macroEnabled.12 content type. Rename an .xlsm to .zip and open it to see these parts.

What is an XLSM file?

XLSM is the macro-enabled version of Excel's modern workbook format, introduced with Excel 2007 alongside .xlsx. Technically it is the same ZIP-based Office Open XML package as XLSX — worksheets, styles, and shared strings stored as XML parts under an xl/ folder — with one crucial addition: a vbaProject.bin part holding a VBA (Visual Basic for Applications) macro project. The format is standardised as ECMA-376 and ISO/IEC 29500. Microsoft deliberately split the two extensions in 2007 so that the default .xlsx cannot contain macros: any workbook with macros must be saved as .xlsm (or the binary .xlsb, or the template .xltm). That makes the extension itself a safety signal — an .xlsx is code-free, while an .xlsm can run VBA.

Macros are small programs that automate repetitive work: reformatting data, generating reports, building custom buttons and forms, or pulling in external data. Businesses lean on XLSM for templates, calculators, dashboards, and data tools where one-click automation matters. The spreadsheet content — cells, formulas, charts, pivot tables — is identical to XLSX; the only functional difference is the bundled macro code. Everything below is about how that package is actually built, and why the macro part is both the point of the format and its main hazard.

The OPC package: a ZIP of XML parts

An XLSM is an Open Packaging Conventions (OPC) package, which is a plain ZIP archive. If you rename a copy to .zip and extract it, you see a small tree of XML files and folders, each with a defined role. The archive begins with the ZIP local-file-header signature 50 4B 03 04 (PK), exactly like any other ZIP, which is why the raw bytes cannot distinguish an XLSM from an XLSX or a .docx.

[Content_Types].xml        maps file extensions/parts to MIME content types
_rels/.rels                package-level relationships (points to the workbook)
docProps/
  core.xml                 author, title, dates
  app.xml                  application metadata
xl/
  workbook.xml             list of sheets, defined names
  _rels/workbook.xml.rels  links workbook -> sheets, styles, vbaProject
  worksheets/sheet1.xml     the cell data and formulas for each sheet
  sharedStrings.xml         de-duplicated table of all cell text
  styles.xml               number formats, fonts, fills, borders
  vbaProject.bin           the VBA macro project  (XLSM only)

Two mechanisms hold this together. [Content_Types].xml declares the type of every part, and it is here that an XLSM announces itself: the workbook part is given the content type application/vnd.ms-excel.sheet.macroEnabled.main+xml rather than the plain XLSX type. The _rels relationship files are the wiring: xl/_rels/workbook.xml.rels contains a relationship of type .../vbaProject pointing at xl/vbaProject.bin. Remove that relationship and the part, and the file becomes a code-free XLSX.

How cells and shared strings are stored

The actual grid lives in xl/worksheets/sheet1.xml (one file per sheet). Each row is a <row> element containing <c> (cell) elements addressed in A1 notation, with the value in a <v> child and any formula in an <f> child. Text values are not stored inline by default. Instead, to avoid repeating the same string thousands of times, each unique piece of text is stored once in xl/sharedStrings.xml, and the cell holds an index into that table with the attribute t="s" (type = shared string):

<c r="A1" t="s"><v>0</v></c>        <!-- text: sharedStrings entry 0 -->
<c r="B1"><v>42</v></c>               <!-- number: 42 -->
<c r="C1"><f>A1&B1</f><v>...</v></c>  <!-- formula + cached result -->

Number formats, fonts, and fills are likewise factored out into styles.xml and referenced by index (the cell's s= attribute), so the sheet XML stays compact. This indirection is why editing an XLSM by hand means touching several parts at once, and why tools read the whole package rather than a single stream.

Inside vbaProject.bin: the macro project

The one part that defines an XLSM, xl/vbaProject.bin, is not XML. It is a binary OLE2 compound file (the same structured-storage container as legacy .doc and .xls), embedded whole inside the ZIP. Within it are storages and streams: a dir stream describing the project and its modules, and one module stream per code module (Module1, Sheet1, ThisWorkbook). Each module stream holds the VBA source together with P-code and a compressed copy, all stored at a per-module offset recorded in the dir stream.

This structure matters for two practical reasons. First, VBA is compiled to P-code for the specific Office version, and Excel may run the P-code without recompiling the source — a quirk that malware has abused (“VBA stomping”) to hide code whose visible source does not match what runs. Second, because vbaProject.bin is a self-contained OLE2 blob, security scanners parse it separately from the XML parts to extract and inspect the macro source. When you save an XLSM back to .xlsx, Excel simply drops this part and its relationship, which is exactly why that conversion removes all macros.

XLSX versus XLSM, byte for byte

The two formats are the same modern Excel workbook with one difference: an XLSM may carry a VBA project and an XLSX may not. They share the ZIP/OPC container, the worksheet XML, the shared-string table, and the styles. The distinguishing marks are concrete and checkable: an XLSM contains xl/vbaProject.bin, and its [Content_Types].xml uses the macroEnabled.12 content type. If you add a macro to an .xlsx and try to save, Excel refuses and prompts you to save as .xlsm; conversely, saving an .xlsm as .xlsx warns that the VBA project will be discarded. The spreadsheet data survives the round trip unchanged — only the code is added or removed.

Opening an XLSM without Excel

Because the data is standard OOXML, many programs read an XLSM. Microsoft Excel is the native application and the only one that runs its VBA reliably. Free alternatives LibreOffice Calc, WPS Office, and OnlyOffice open the cells, formulas, and charts; LibreOffice and OnlyOffice can execute many macros, but VBA compatibility is partial, so a complex Excel macro may not run. Google Sheets and Excel for the web open the data after upload but deliberately do not run VBA (Sheets uses its own Apps Script), which makes them a safe way to view an untrusted workbook. If you only need a plain data table, exporting to CSV drops every macro along with formatting and formulas.

Safety: the VBA macro execution path

XLSM is the high-risk member of the Excel family precisely because it can run code, and its VBA macros are a classic malware vector. The attack pattern is specific: an emailed .xlsm presents a lure and urges the recipient to click Enable Content. Doing so authorises the VBA project to run, and an Auto_Open or Workbook_Open handler fires immediately — from there the macro can call Shell or CreateObject("WScript.Shell") to download and execute a payload outside Excel entirely. Nothing runs while you merely open the file to view it; the danger is the moment you enable macros.

Two Microsoft defences sit in this path and should be left on. Files that arrive from the internet or email carry a Mark of the Web (a hidden zone marker), and Excel now blocks macros in such files outright, showing a red banner rather than the “Enable Content” button; untrusted files also open in Protected View, a sandbox with no macro execution. Only enable macros in an .xlsm you specifically expect from a sender you trust. If you just need the numbers, open the file in Google Sheets or Excel for the web (which never run VBA), or save it as .xlsx to strip the code. Treat any unsolicited “enable macros” request as hostile.

References