Open almost any XLSX file produced by a Windows copy of Excel that has ever shown a print preview, and you will find a folder called xl/printerSettings/ filled with binary blobs named printerSettings1.bin, printerSettings2.bin, and so on — one per worksheet that ever cached a print configuration. These files are raw Win32 DEVMODE structures, and they carry the printer’s exact device name, the queue path, the driver version, the paper tray, the duplex preference, and frequently a chunk of vendor-specific extension data that names the user, the department, or the floor of the office. The Document Inspector does not touch them. Save As does not regenerate them. They travel with the workbook to every recipient who unzips it. This post walks through what is actually inside the printerSettings binary, what each field reveals, why Office leaves it embedded, and exactly how to strip it before a file leaves your organization.
Excel inherited its printing architecture from a Windows world where every spreadsheet might be printed on a different device, and where any change of paper size, orientation, or tray would invalidate the page layout the user spent time arranging. To preserve that layout across reopens, Excel caches the print configuration of each worksheet at save time. The cache is not a list of human-readable settings — it is the raw Win32 DEVMODE structure handed back to Excel by the printer driver, written byte-for-byte into a separate file inside the XLSX.
The intent was a usability fix: open the workbook on a different machine, hit File > Print, and Excel can show you exactly the layout the original author saw. The side effect is that every workbook now carries a snapshot of the author’s printer device — including network paths, queue names, and driver-specific extension data — into every recipient’s machine.
Every worksheet keeps its own printer cache. A workbook with twelve sheets that have all been print-previewed at least once will end up with twelve separate printerSettingsN.bin blobs — potentially each from a different printer if the author printed different sheets to different devices. The blobs are not deduplicated, even when several sheets share the same configuration.
An XLSX is a ZIP archive. The printer settings live in a flat folder at xl/printerSettings/, and each one is wired to a specific worksheet through the worksheet’s own relationships file.
// XLSX layout fragment showing where printerSettings live
workbook.xlsx (zip)
├── [Content_Types].xml // declares printerSettings content type
├── xl/
│ ├── workbook.xml
│ ├── printerSettings/
│ │ ├── printerSettings1.bin // <-- raw DEVMODE for sheet1
│ │ ├── printerSettings2.bin // <-- raw DEVMODE for sheet2
│ │ └── printerSettings3.bin // ...
│ └── worksheets/
│ ├── sheet1.xml
│ └── _rels/
│ ├── sheet1.xml.rels // links sheet1 to printerSettings1.bin
│ └── sheet2.xml.rels // ...
The relationship is one-way: each sheetN.xml.rels file declares a relationship of type .../relationships/printerSettings pointing at one of the blobs. The worksheet XML itself contains a small <pageSetup> element with a relationship ID (r:id="rId1") that ties the human-readable layout settings to the binary blob.
// Excerpt from xl/worksheets/_rels/sheet1.xml.rels
<Relationship
Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings"
Target="../printerSettings/printerSettings1.bin"/>
// Excerpt from xl/worksheets/sheet1.xml
<pageSetup paperSize="9" orientation="landscape" r:id="rId1"/>
The presence of xl/printerSettings/ at all is itself a signal. Workbooks created or last saved by non-Microsoft writers (LibreOffice, openpyxl, xlsxwriter, server-side libraries) typically do not embed printer settings. A workbook that contains printerSettings1.bin almost certainly passed through Microsoft Excel on Windows immediately before being shared.
Each printerSettingsN.bin is a Windows GDI DEVMODE structure, defined in the public Win32 SDK header wingdi.h. The first 220 bytes are a fixed-layout struct; everything after is driver-specific extension data of variable length. The fixed part begins with a string field, which is precisely why it leaks the most identifying piece of information first.
| Offset | Field | What It Reveals |
|---|---|---|
| 0x00 | dmDeviceName | 32-char UTF-16 string. The exact printer name as installed on the author’s machine. |
| 0x40 | dmSpecVersion | Driver spec version. Typically 0x0401 (Windows 2000+) or higher; ties the file to a Windows generation. |
| 0x42 | dmDriverVersion | Vendor driver version number. Pinpoints the exact build of the printer driver installed. |
| 0x46 | dmSize / dmDriverExtra | Sizes of the fixed and extension portions. The extension can be hundreds of bytes of vendor-defined data. |
| 0x4E | dmOrientation | 1 = portrait, 2 = landscape. |
| 0x50 | dmPaperSize / dmPaperWidth / dmPaperLength | Standard size code (e.g., 9 = A4, 1 = Letter) or explicit width/height in tenths of a millimetre. |
| 0x5C | dmDefaultSource | Which paper tray the document defaults to. Reveals whether the author printed from a specific tray (e.g., Letterhead, Manual Feed). |
| 0x5E | dmPrintQuality / dmYResolution | DPI setting. Distinguishes high-end production printers from desktop ones. |
| 0x60 | dmColor / dmDuplex / dmCollate | Colour vs monochrome, single- or double-sided, collation preference. Office hygiene fingerprint. |
| 0x6E | dmFormName | 32-char UTF-16 string. Custom paper form name — often something like “Legal Tray 3” or “Cheque Stock”. |
| 0xDC+ | Driver-specific extension | Vendor-defined bytes. Frequently contains user names, queue paths, watermark strings, and tray accounting codes. |
The first field, dmDeviceName, is the headline leak. It is a fixed-width UTF-16 string at the very start of the file, easy to read with any hex viewer or a one-line script. In a corporate environment, this string is almost never an anonymous label.
Printer names installed on corporate machines typically encode the office, the floor, and the team: HP-LJ-Floor3-Marketing, CanoniRADV-FinSeoul-9F, RICOH-LegalDept-CheckPrinter, \\\\PRINT-SVR-01\\HR-Confidential. A single printerSettings blob can pin the workbook’s author down to a specific desk in a specific building of a specific subsidiary, without ever touching the workbook’s document properties.
Many corporate printers are installed not as locally-named devices but as queues hosted on a print server. The installed name is then a UNC path of the form \\\\PRINTSVR-LON-01\\Finance-Color. Excel embeds this string verbatim. A recipient who reads printerSettings1.bin learns:
Legal-Confidential tells a recipient the author has access to a queue that exists for sensitive documents.PRINTSVR-LON-01 places the author in a London office. Multiple workbooks from the same author with different print servers reveal travel patterns.For organisations that have invested in segregating internal infrastructure from public visibility, every printerSettings blob in an externally-shared workbook is a small leak from inside the perimeter.
After the 220-byte fixed structure, every DEVMODE contains a driver-specific extension whose contents are entirely up to the printer vendor. There is no formal schema, and no requirement that drivers strip personally-identifying data. In practice, the extension block is where the most surprising leakage happens.
Many enterprise printers (Canon, Ricoh, Xerox, Konica Minolta) support “follow-me printing” or per-user accounting. The driver embeds the user’s account ID into the extension block so the print job can be billed back to the right cost centre. That ID frequently turns out to be the author’s Active Directory username or employee number, sitting in the file long after the print preview that produced it.
Drivers configured to overlay watermarks (“DRAFT”, “CONFIDENTIAL”, “COPY 1 OF 5”, sometimes the author’s name) often persist the watermark text inside the extension block. Even if the watermark itself never made it onto a physical page, the string is now in the file.
Production printers carry custom ICC profile names tied to specific paper stocks — CompanyName-CoverStock-2025, Annual-Report-Glossy. These leak the existence of internal print runs and project codenames the author was working on at the time.
Some drivers persist the mapping of trays to forms. Tray names like Tray3-LegalLetterhead or ManualFeed-CheckStock survive in the binary and reveal what the author had configured on their device.
The lifecycle of a printerSettingsN.bin is silent and aggressive. Excel writes one out under any of the following circumstances, none of which involve actually printing anything on paper:
DEVMODE and caches it on the sheet immediately.DEVMODE stays.Microsoft Print to PDF, but sometimes a third-party PDF driver that names the user).A common assumption is that “Save As” produces a clean copy of the file. It does not for printer settings. The DEVMODE cached on each worksheet is copied verbatim to the new file. Saving from Excel on a different machine does not regenerate the blob unless the user actively opens Page Setup on each worksheet, which essentially nobody does before sharing.
The Document Inspector (File > Info > Check for Issues > Inspect Document) has categories for hidden sheets, comments, document properties, custom XML, ink annotations, headers and footers, and several others. printerSettings/*.bin is in none of them. Running the Inspector on a workbook with a fully-populated cache and removing every issue it flags will leave every byte of every DEVMODE blob untouched.
This is partly historical — the Inspector was designed before the modern OOXML format made the binaries trivially extractable — and partly intentional. Microsoft views the print configuration as a usability feature whose removal would degrade the recipient’s experience. From a privacy standpoint, the result is that the most user-trusted “cleaning” tool in Office leaves the printer-settings layer entirely intact.
The blob is just bytes inside a ZIP. Three approaches let you read every printerSettings file in a workbook in a few seconds, without ever opening Excel.
# 1. List every printer settings blob in the file
unzip -l workbook.xlsx | grep printerSettings
# 2. Pull the device name out of the first 64 bytes
# (UTF-16LE, null-padded to 32 wide chars)
unzip -p workbook.xlsx "xl/printerSettings/printerSettings1.bin" | \
head -c 64 | iconv -f UTF-16LE -t UTF-8
# 3. Hex-dump the first 256 bytes for a quick visual scan
unzip -p workbook.xlsx "xl/printerSettings/printerSettings1.bin" | \
xxd | head -16
For programmatic auditing, a small Python script enumerates every blob in a workbook and decodes the human-readable fields:
# Walk every printerSettings blob and dump device + form names
import zipfile, struct
def read_devmode(blob):
device = blob[0:64].decode("utf-16-le").rstrip("\\x00")
spec_ver, drv_ver, dm_size, dm_extra = struct.unpack_from("<HHHH", blob, 64)
orientation = struct.unpack_from("<H", blob, 78)[0]
paper = struct.unpack_from("<H", blob, 80)[0]
form = blob[110:174].decode("utf-16-le", "ignore").rstrip("\\x00")
return dict(device=device, driver_version=drv_ver, orientation=orientation,
paper=paper, form=form, dm_size=dm_size, dm_extra=dm_extra)
with zipfile.ZipFile("workbook.xlsx") as z:
for name in z.namelist():
if name.startswith("xl/printerSettings/"):
print(name, read_devmode(z.read(name)))
The output is a small table of every cached device, every paper size, and the size of the driver-specific extension. The extension itself can be sliced out with blob[dm_size:dm_size + dm_extra] and scanned for embedded UTF-16 strings — a one-line additional step that almost always finds at least one identifier the author did not realise was there.
In real audits of workbooks shared externally by mid-size and large organisations, the printerSettings blob consistently leaks a recognisable set of facts:
HP-LJ-NYC-37F-East place the author on a specific floor of a specific building.Finance-Color, Legal-Confidential, HR-Payroll. The queue name reveals the function whether the workbook’s contents do or not.sAMAccountName.dmSpecVersion and the size of the extension narrows the OS down to a Windows version range. A workbook claiming to be from a current Office build but carrying a 0x0401 spec version was last touched on a much older OS.dmDeviceName — revealing licensed software inventory at the author’s organisation.Recipes circulated internally for “cleaning” Excel files — clear author name, run Document Inspector, save as new file — do not touch printerSettings/*.bin. The blob travels with the workbook through every step. Even copying-pasting all sheets into a new blank workbook frequently re-creates a cache the moment the recipient opens Page Setup.
Cleaning printerSettings requires explicit action. Excel will not do it for you, and there is no UI button that triggers it. Four approaches in increasing order of robustness.
With the workbook open on a generic device (e.g., Microsoft Print to PDF), open Page Setup on every worksheet and click OK. Excel rewrites each DEVMODE for the current device, replacing the corporate-printer references with the generic one. The blob is still present, but the identifying strings are gone. This is the lowest-friction option for files staying inside Office.
The cleanest option. Strip the entire xl/printerSettings/ folder, the relationship entries that point at it, and the corresponding overrides in [Content_Types].xml. Excel happily opens the file and rebuilds a fresh cache only if the recipient opens Page Setup — which is the recipient’s device, not yours.
A short Python script removes every printerSettings binary and the associated relationship and content-type entries:
import zipfile, re
from pathlib import Path
src, dst = Path("in.xlsx"), Path("out.xlsx")
with zipfile.ZipFile(src) as zin, \
zipfile.ZipFile(dst, "w", zipfile.ZIP_DEFLATED) as zout:
for item in zin.infolist():
if item.filename.startswith("xl/printerSettings/"):
continue
data = zin.read(item.filename)
if item.filename.endswith(".rels"):
data = re.sub(rb"<Relationship[^/]*printerSettings[^/]*/>", b"", data)
if item.filename == "[Content_Types].xml":
data = re.sub(rb"<Override[^/]*printerSettings[^/]*/>", b"", data)
zout.writestr(item, data)
The pageSetup element in each worksheet still references the (now missing) relationship by ID, but Excel tolerates it gracefully and falls back to default page settings. For strict OOXML conformance, also strip the r:id attribute from each <pageSetup> tag in the worksheet XML.
For organisations that share workbooks regularly, build a server-side step into the file-sharing pipeline that opens each XLSX, deletes the printerSettings folder and its references, and re-zips. This composes well with the parallel sanitisation steps for external links, defined names, and calculation chain — all of which the same pipeline can handle in one pass.
Run this checklist against any workbook leaving your organisation, especially if it has ever been opened on a Windows copy of Excel:
xl/printerSettings/ exists in the ZIP at all?dmDriverExtra) for embedded UTF-16 strings — account IDs, watermarks, project codenames?xl/printerSettings/ entirely along with its .rels and [Content_Types].xml entries?xl/printerSettings/*.bin is the most overlooked metadata layer in modern XLSX files. The blob exists for a legitimate usability reason — preserving page layout across machines — but the price is that every workbook produced by a Windows copy of Excel now carries a per-sheet snapshot of the author’s printer device, complete with UNC paths, queue names, account IDs, watermark strings, and driver-specific identifiers that frequently include the author’s username or the codenames of internal projects. The Document Inspector ignores it, Save As preserves it, and copy-paste-into-new-workbook does not regenerate it.
For workbooks staying inside an organisation, the cost is small — recipients all share the same network of printers anyway. For workbooks crossing the perimeter, the printer settings are a small but reliable inside-the-fence beacon. The only durable defence is to either reset Page Setup on a generic device on every sheet, or strip xl/printerSettings/ from the ZIP entirely. Both are inexpensive, neither degrades the recipient’s experience in any meaningful way, and either eliminates a leak that nobody — including most security teams — ever thinks to look for.
Another set of UNC paths and server hostnames that travel quietly with your XLSX files.
Where every metadata layer lives inside an XLSX, including the binary printerSettings folder.
The parallel hidden layer that the Document Inspector also leaves entirely intact.