Claris has extended the FMUpgradeTool in the recent release, providing support for adding/replacing/deleting more object types, and also added the ability to generate completely new fmp12 files.

Next to the new features, there have also been some undocumented breaking changes, though.

I used the FMUpgradeTool in version 22.0.2 to inject accounts into fmp12 files as part of a deployment process. In short: a file is distributed to several servers, and while an update routine is running, the file should get site-specific accounts added, using passwords that are available only during runtime of the deployment process (and thus obviously not during distribution of the file).

Working patch file in v22

In v22 you could add accounts and set their plaintext passwords, for example, like this:

[...]
    <Account id="100" kind="0" type="FileMaker" enable="True">
        <Description>this account was injected via FMUpgradeTool</Description>
        <Authentication>
            <AccountName>my-user</AccountName>
            <Password><![CDATA[my-password]]></Password>
        </Authentication>
        <PrivilegeSetReference id="1" name="[Full Access]"></PrivilegeSetReference>
    </Account>
[...]

Applying it with the command: /Library/FileMaker\ Server/Database\ Server/bin/FMUpgradeTool --update -src_path my-file.fmp12 -src_account account -src_pwd password -patch_path patch.xml -dest_path my-file-patched.fmp12 -v -force

This would create a my-user account in the my-file-patched.fmp12 with the password my-password and assign it the [Full Access] privilege set.

Not working in v26 anymore

Doing the same in v26 now will result in the account my-user being added, but with an empty password. And without any error being logged. Not ideal :-)

Since there’s no XML spec available, I tried to figure out myself how the XML structure might have changed between versions. At first, by creating a new XML representation of accounts using the FMDeveloperTool:

./FMDeveloperTool --saveAsXML my-file.fmp12 user password -t /tmp/out.xml -cl AccountsCatalog

This was obviously not immediately helpful as the resulting XML never contains plaintext passwords. The structure looks like this:

<Account id="100" kind="0" type="FileMaker" enable="True">
    <UUID modifications="5" userName="admin" accountName="admin" timestamp="2025-07-25T14:38:02">91AFFC59-83CA-410F-A231-6689A9923871</UUID>
    <TagList></TagList>
    <Description></Description>
    <Authentication>
        <AccountName>my-user</AccountName>
        <PasswordEncrypted>
            <Context>9wwUAlY5Vj4e/g==</Context>
            <Data>/iKVMnF8rp3rXOZ4+Qdmr6/WrZ4=</Data>
        </PasswordEncrypted>
    </Authentication>
    <PrivilegeSetReference id="1" name="[Full Access]"></PrivilegeSetReference>
</Account>

I spent a little bit of time trying to debug the binary, but eventually came to the conclusion that the plaintext password route has probably been removed for good.

An interesting artifact was the Draco::kXMLEngine_Insecure_Password_Tag symbol which led me to the INSECURE_PASSWORD tag name.

During debugging, I could only find that while processing the patch XML file the behavior for INSECURE_PASSWORD and PasswordEncrypted (as emitted by --saveAsXML) seem to be exactly the same.

Thus, creating a patch file like the following is actually accepted and works the same as PasswordEncrypted.

<Account id="100" kind="0" type="FileMaker" enable="True">
    <Description>this account was injected via FMUpgradeTool</Description>
    <Authentication>
        <AccountName>my-user</AccountName>
        <INSECURE_PASSWORD>
            <Context>9wwUAlY5Vj4e/g==</Context>
            <Data>/iKVMnF8rp3rXOZ4+Qdmr6/WrZ4=</Data>
        </INSECURE_PASSWORD>
    </Authentication>
    <PrivilegeSetReference id="1" name="[Full Access]"></PrivilegeSetReference>
</Account>

Maybe it’s a bug or maybe something I didn’t completely understand from the assembly. In any case it doesn’t really help if you want to inject accounts with specific passwords.

Figuring out Context and Data

Since the FMUpgradeTool doesn’t accept plaintext passwords anymore, the only way to inject accounts into a file would be to understand what Context and Data in the PasswordEncrypted node contain.

To figure this out, I went back to my exploration of the fmp12 file format from two years ago.

To make it short: the Context is the salt, just how it is also stored in the fmp12 file. And Data is the result from the key derivation function (PBKDF2) – again, the same as in the fmp12 file.

This all makes sense. The FMUpgradeTool now probably just transfers things over without re-computing them again.

Based on my earlier research, I could just re-create these values by generating a random salt, applying the same obfuscation techniques to a chosen password, and feeding it into the PBKDF2 function. The result can go base64-encoded into the patch file and will then successfully inject an account with the desired password.

Small program to create valid account passwords

I created a program to output the valid account password XML structure for a chosen password. So if you have a similar need, you can just run:

./fm-upgrade-keygen <password>

And get something like this back:

<PasswordEncrypted>
    <Context>GrgUCliZdbvgdA==</Context>
    <Data>9SjtyMbtan7trkinfthMvIicYQ0=</Data>
</PasswordEncrypted>

You can download fm-upgrade-keygen for macOS (arm) here.

Intended way? Is there one?

In parallel to my own research, I contacted Claris support, asking if there’s an intended/official way of injecting new accounts into files. I haven’t heard back yet, but will update the post in case I do.

The source code of my small utility is currently not public. But most of the steps to figure this out you can find in my fmp12 article. If the intended way (if there is one and I hear back) aligns with my own procedure, I’m happy to release the source code as well.