CVE-2023-37912 (Java, published 2023-10-25T18:17Z)
Description: value: XWiki Rendering is a generic Rendering system that converts textual input in a given syntax into another syntax. Prior to version 14.10.6 of `org.xwiki.platform:xwiki-core-rendering-macro-footnotes` and `org.xwiki.platform:xwiki-rendering-macro-footnotes` and prior to version 15.1-rc-1 of `org.xwiki.platform:xwiki-rendering-macro-footnotes`, the footnote macro executed its content in a potentially different context than the one in which it was defined. In particular in combination with the include macro, this allows privilege escalation from a simple user account in XWiki to programming rights and thus remote code execution, impacting the confidentiality, integrity and availability of the whole XWiki installation. This vulnerability has been patched in XWiki 14.10.6 and 15.1-rc-1. There is no workaround apart from upgrading to a fixed version of the footnote macro.
Severity: nan (CVSS v3 base score: 8.8)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/xwiki/xwiki-rendering
Files changed:
xwiki-rendering-macros/xwiki-rendering-macro-footnotes/pom.xml
xwiki-rendering-macros/xwiki-rendering-macro-footnotes/src/main/java/org/xwiki/rendering/internal/macro/footnote/FootnoteMacro.java
xwiki-rendering-macros/xwiki-rendering-macro-footnotes/src/main/java/org/xwiki/rendering/internal/macro/footnote/PutFootnotesMacro.java
xwiki-rendering-macros/xwiki-rendering-macro-footnotes/src/test/java/org/xwiki/rendering/macro/footnote/ExecutedContentMacro.java
xwiki-rendering-macros/xwiki-rendering-macro-footnotes/src/test/resources/META-INF/components.txt
xwiki-rendering-macros/xwiki-rendering-macro-footnotes/src/test/resources/macrofootnote3.test
xwiki-rendering-macros/xwiki-rendering-macro-footnotes/src/test/resources/macrofootnote6.test
Commit message: XRENDERING-688: Improve footnote rendering (#246)

* Parse and execute the footnote's content directly instead of from the
  putFootnotes macro.
* Use the id generator to generate unique ids.
* Adapt the existing test to expect nested footnote support.
* Add new tests to test some more corner cases.
* Wrap the content of the footnote in a composite block to make it
  easier to handle.
* Remove Checkstyle suppressions.

Vulnerable code:
    <!-- {{putFootnotes}} is a complex macro that needs to instantiate several different XDOM classes -->
    <checkstyle.suppressions.location>${basedir}/src/main/checkstyle/checkstyle-suppressions.xml</checkstyle.suppressions.location>
<?xml version="1.0" encoding="UTF-8"?>

<!--
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.

<!DOCTYPE suppressions PUBLIC
     "-//Puppy Crawl//DTD Suppressions 1.0//EN"
     "http://www.puppycrawl.com/dtds/suppressions_1_0.dtd">

<suppressions>
  <!-- {{putFootnotes}} is a complex macro that needs to instantiate several different XDOM classes -->
  <suppress checks="ClassDataAbstractionCoupling" files="PutFootnotesMacro.java" />
</suppressions>
        return Collections.emptyList();
import java.util.ListIterator;
import org.xwiki.rendering.block.match.ClassBlockMatcher;
import org.xwiki.rendering.macro.MacroContentParser;
import org.xwiki.rendering.macro.MacroExecutionException;
     * Used to parse the content of the macro.
    private MacroContentParser contentParser;
        throws MacroExecutionException
        // Get the list of footnotes in the document
        List<MacroMarkerBlock> footnotes =
            root.getBlocks(new ClassBlockMatcher(MacroMarkerBlock.class), Block.Axes.DESCENDANT);
        for (ListIterator<MacroMarkerBlock> it = footnotes.listIterator(); it.hasNext();) {
            MacroMarkerBlock macro = it.next();
            if (FootnoteMacro.MACRO_NAME.equals(macro.getId())) {
                continue;
            } else if (PutFootnotesMacro.MACRO_NAME.equals(macro.getId())) {
                macro.getParent().replaceChild(Collections.<Block>emptyList(), macro);
            }
            it.remove();
        if (footnotes.isEmpty()) {
            return result;
        NumberedListBlock container = new NumberedListBlock(Collections.<Block>emptyList());
        container.setParameter(CLASS_ATTRIBUTE_NAME, "footnotes");
        Block footnoteResult;
        int counter = 1;
        for (MacroMarkerBlock footnote : footnotes) {
            footnoteResult = processFootnote(footnote, counter, context);
            if (footnoteResult != null) {
                container.addChild(footnoteResult);
                counter++;
        return Collections.<Block>singletonList(container);
     * Processes a {{footnote}} macro, by generating a footnote element to insert in the footnote list and a reference
     * @param footnoteMacro the {{footnote}} macro element
     * @param context the execution context of the macro
     * @throws MacroExecutionException if the footnote content cannot be further processed
    private ListItemBlock processFootnote(MacroMarkerBlock footnoteMacro, int counter,
        MacroTransformationContext context) throws MacroExecutionException
        String content = footnoteMacro.getContent();
        if (StringUtils.isBlank(content)) {
            content = " ";
        Block referenceBlock = createFootnoteReferenceBlock(counter);
        ListItemBlock footnoteBlock = createFootnoteBlock(content, counter, context);
        if (referenceBlock != null && footnoteBlock != null) {
            addFootnoteRef(footnoteMacro, referenceBlock);
            return footnoteBlock;
        return null;
    private Block createFootnoteReferenceBlock(int counter)
        reference.setAnchor(FOOTNOTE_ID_PREFIX + counter);
        result.setParameter(ID_ATTRIBUTE_NAME, FOOTNOTE_REFERENCE_ID_PREFIX + counter);
        result.setParameter(CLASS_ATTRIBUTE_NAME, "footnoteRef");
     * actual footnote text, parsed into XDOM.
     * @param content the string representation of the actual footnote text; the content of the macro
     * @param counter the current footnote counter
     * @param context the macro transformation context, used for obtaining the correct parser for parsing the content
     * @throws MacroExecutionException if parsing the content fails
    private ListItemBlock createFootnoteBlock(String content, int counter, MacroTransformationContext context)
        throws MacroExecutionException
        List<Block> parsedContent;
        try {
            parsedContent = this.contentParser.parse(content, context, false, true).getChildren();
        } catch (MacroExecutionException e) {
            parsedContent = Collections.<Block>singletonList(new WordBlock(content));
        }
        reference.setAnchor(FOOTNOTE_REFERENCE_ID_PREFIX + counter);
        result.setParameter(ID_ATTRIBUTE_NAME, FOOTNOTE_ID_PREFIX + counter);
        result.addChildren(parsedContent);
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1]]] [false]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1]]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1]]
endDocument

Fixed code:
import javax.inject.Inject;
import org.xwiki.rendering.macro.MacroContentParser;
    /**
     * Used to parse the content of the footnote.
     */
    @Inject
    private MacroContentParser contentParser;


        return this.contentParser.parse(content, context, true, true).getChildren();
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.xwiki.rendering.block.CompositeBlock;
import org.xwiki.rendering.block.match.MacroMarkerBlockMatcher;
import org.xwiki.rendering.listener.reference.ResourceReference;
import org.xwiki.rendering.util.IdGenerator;
    /** Class name for the reference to the footnote. */
    private static final String FOOTNOTE_REF_CLASS_NAME = "footnoteRef";

     * Internal data structure for representing a footnote.
    private static class Footnote
    {
        /**
         * The HTML id of the footnote.
         */
        private String id;

        /**
         * The HTML id of the reference to the footnote (for jumping back).
         */
        private String referenceId;

        /**
         * The macro marker block of the footnote macro.
         */
        private final MacroMarkerBlock macroMarkerBlock;

        /**
         * The content of the footnote.
         */
        private CompositeBlock content;

        /**
         * Create a new footnote for the given footnote macro marker block.
         * <p>
         * If the only child is a format block with a reference id, the ids are extracted from the format block and
         * its link child, otherwise the content of the macro marker is set as content and ids should be set later.
         *
         * @param macroMarkerBlock the footnote macro marker block
         */
        Footnote(MacroMarkerBlock macroMarkerBlock)
        {
            this.macroMarkerBlock = macroMarkerBlock;

            if (macroMarkerBlock.getChildren().size() == 1
                && macroMarkerBlock.getChildren().get(0) instanceof FormatBlock
                && StringUtils.startsWith(macroMarkerBlock.getChildren().get(0).getParameter(ID_ATTRIBUTE_NAME),
                FOOTNOTE_REFERENCE_ID_PREFIX))
            {
                Block formatBlock = macroMarkerBlock.getChildren().get(0);
                if (!formatBlock.getChildren().isEmpty() && formatBlock.getChildren().get(0) instanceof LinkBlock) {
                    LinkBlock linkBlock = (LinkBlock) formatBlock.getChildren().get(0);
                    ResourceReference reference = linkBlock.getReference();
                    if (reference instanceof DocumentResourceReference) {
                        this.id = ((DocumentResourceReference) reference).getAnchor();
                    }
                }
                this.referenceId = formatBlock.getParameter(ID_ATTRIBUTE_NAME);
            } else {
                this.content = new CompositeBlock(macroMarkerBlock.getChildren());
            }
        }
    }

    private Logger logger;
        List<MacroMarkerBlock> macroMarkerBlocks =
            root.getBlocks(new MacroMarkerBlockMatcher(PutFootnotesMacro.MACRO_NAME, FootnoteMacro.MACRO_NAME),
                Block.Axes.DESCENDANT);

        Map<String, Footnote> footnotes = new LinkedHashMap<>();

        // Give footnotes without id temporary, numeric ids, we don't need to retrieve them by id.
        AtomicInteger temporaryId = new AtomicInteger(0);
        // Get the list of footnotes in the document
        macroMarkerBlocks.stream()
            .filter(macro -> FootnoteMacro.MACRO_NAME.equals(macro.getId()))
            .map(Footnote::new)
            .forEach(footnote -> footnotes.put(
                Objects.requireNonNullElseGet(footnote.id, () -> String.valueOf(temporaryId.getAndIncrement())),
                footnote));

        // Collect the footnote content from the existing footnote lists and remove them.
        macroMarkerBlocks.stream()
            .filter(macro -> PutFootnotesMacro.MACRO_NAME.equals(macro.getId()))
            .forEach(macro -> collectFootnoteContents(macro, footnotes));

        IdGenerator idGenerator = null;
        if (context.getXDOM() != null) {
            idGenerator = context.getXDOM().getIdGenerator();

        if (!footnotes.isEmpty()) {
            NumberedListBlock container = new NumberedListBlock(Collections.emptyList());
            container.setParameter(CLASS_ATTRIBUTE_NAME, "footnotes");
            result = Collections.singletonList(container);

            int counter = 1;
            for (Footnote footnote : footnotes.values()) {
                if (footnote.content != null) {
                    Block footnoteResult = processFootnote(footnote, counter, idGenerator);
                    container.addChild(footnoteResult);
                    counter++;
                } else {
                    this.logger.warn("No content for footnote [{}] found, ignoring it.",
                        footnote.macroMarkerBlock);
                }
            }
        return result;
    }
    /**
     * Collect and remove footnote contents from the given putFootnotes macro marker block.
     *
     * @param macro the putFootnotes macro marker block from which footnote contents shall be collected
     * @param footnotes the footnotes where the content shall be collected
     */
    private void collectFootnoteContents(MacroMarkerBlock macro, Map<String, Footnote> footnotes)
    {
        if (macro.getChildren().size() == 1 && macro.getChildren().get(0) instanceof NumberedListBlock) {
            for (Block listItemBlock : macro.getChildren().get(0).getChildren()) {
                if (listItemBlock.getChildren().size() == 3
                    && listItemBlock.getChildren().get(2) instanceof CompositeBlock
                    && StringUtils.startsWith(listItemBlock.getChildren().get(0).getParameter(ID_ATTRIBUTE_NAME),
                    FOOTNOTE_ID_PREFIX))
                {
                    CompositeBlock footnoteContent = (CompositeBlock) listItemBlock.getChildren().get(2);
                    String id = listItemBlock.getChildren().get(0).getParameter(ID_ATTRIBUTE_NAME);
                    if (footnotes.containsKey(id)) {
                        footnotes.get(id).content = footnoteContent;
                    } else {
                        this.logger.warn("Could not find footnote marker for footnote [{}], ignoring it.",
                            footnoteContent);
                    }
                }
        macro.getParent().removeBlock(macro);
     * Processes a footnote macro, by generating a footnote element to insert in the footnote list and a reference
     * @param footnote the footnote
    private ListItemBlock processFootnote(Footnote footnote, int counter, IdGenerator idGenerator)
        if (footnote.referenceId == null) {
            footnote.referenceId = generateId(counter, FOOTNOTE_REFERENCE_ID_PREFIX, idGenerator);

        if (footnote.id == null) {
            footnote.id = generateId(counter, FOOTNOTE_ID_PREFIX, idGenerator);
        }

        Block referenceBlock = createFootnoteReferenceBlock(counter, footnote.id, footnote.referenceId);
        ListItemBlock footnoteBlock = createFootnoteBlock(footnote.content, footnote.id, footnote.referenceId);
        addFootnoteRef(footnote.macroMarkerBlock, referenceBlock);
        return footnoteBlock;
    }

    private String generateId(int counter, String idPrefix, IdGenerator idGenerator)
    {
        String footnoteId = idPrefix + counter;
        if (idGenerator != null) {
            footnoteId = idGenerator.generateUniqueId(footnoteId.substring(0, 1), footnoteId.substring(1));

        return footnoteId;
     * @param footnoteId the id of the footnote
     * @param referenceId the id of the reference
    private Block createFootnoteReferenceBlock(int counter, String footnoteId, String referenceId)
        reference.setAnchor(footnoteId);
        result.setParameter(ID_ATTRIBUTE_NAME, referenceId);
        result.setParameter(CLASS_ATTRIBUTE_NAME, FOOTNOTE_REF_CLASS_NAME);
     * actual footnote content.
     * @param content the block with the actual footnote content
     * @param footnoteId the id of the footnote
     * @param referenceId the id of the reference
    private ListItemBlock createFootnoteBlock(CompositeBlock content, String footnoteId, String referenceId)
        reference.setAnchor(referenceId);
        result.setParameter(ID_ATTRIBUTE_NAME, footnoteId);
        result.addChild(content);
/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.rendering.macro.footnote;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.xwiki.component.annotation.Component;
import org.xwiki.rendering.block.Block;
import org.xwiki.rendering.macro.AbstractNoParameterMacro;
import org.xwiki.rendering.macro.MacroContentParser;
import org.xwiki.rendering.macro.MacroExecutionException;
import org.xwiki.rendering.macro.descriptor.DefaultContentDescriptor;
import org.xwiki.rendering.transformation.MacroTransformationContext;

/**
 * Executed content macro used in some {@code *.test} files.
 * <p>
 * This macro executes its content and thus allows putFootnotes macros to be executed early.
 *
 * @version $Id$
 */
@Component
@Named("executedcontent")
@Singleton
public class ExecutedContentMacro extends AbstractNoParameterMacro
{
    /**
     * The parser used to parse the content.
     */
    @Inject
    private MacroContentParser contentParser;

    /**
     * Default constructor.
     */
    public ExecutedContentMacro()
    {
        super("Executed Content Macro", "Executes its content.",
            new DefaultContentDescriptor("Content", true, Block.LIST_BLOCK_TYPE));
    }

    @Override
    public boolean supportsInlineMode()
    {
        return false;
    }

    @Override
    public List<Block> execute(Object parameters, String content, MacroTransformationContext context)
        throws MacroExecutionException
    {
        return this.contentParser.parse(content, context, true, context.isInline()).getChildren();
    }
}
org.xwiki.rendering.macro.footnote.ExecutedContentMacro
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1-1]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1-1]]] [false]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1-1]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1-1]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1-1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1-1]]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1-1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1-1]]
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1]]] [false]
onWord [2]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1]]
beginListItem
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1]]
onWord [^]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1]]
onSpace
onSpace
onWord [content]
endListItem
endDocument
.runTransformations
.#-----------------------------------------------------
.input|xwiki/2.0
.# Verify that several footnotes and putFootnotes markers work.
.#-----------------------------------------------------
Footnote{{footnote}}content 1{{/footnote}} {{footnote}}content 2{{/footnote}}

{{putFootnotes/}}

{{executedcontent}}
{{footnote}}Inner footnote{{/footnote}}
{{/executedcontent}}

{{executedcontent}}
{{footnote}}Second inner footnote{{/footnote}}
{{/executedcontent}}


{{footnote}}These are the footnotes:

{{putFootnotes/}}

{{/footnote}}

{{putFootnotes/}}
.#-----------------------------------------------------
.expect|event/1.0
.#-----------------------------------------------------
beginDocument
beginParagraph
onWord [Footnote]
beginMacroMarkerInline [footnote] [] [content 1]
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1-2]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1-2]]] [false]
onWord [1]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1-2]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1-2]]
endMacroMarkerInline [footnote] [] [content 1]
onSpace
beginMacroMarkerInline [footnote] [] [content 2]
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_2]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_2]]] [false]
onWord [2]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_2]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_2]]
endMacroMarkerInline [footnote] [] [content 2]
endParagraph
beginMacroMarkerStandalone [executedcontent] [] [{{footnote}}Inner footnote{{/footnote}}]
beginMacroMarkerStandalone [footnote] [] [Inner footnote]
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1]]] [false]
onWord [3]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1]]
endMacroMarkerStandalone [footnote] [] [Inner footnote]
endMacroMarkerStandalone [executedcontent] [] [{{footnote}}Inner footnote{{/footnote}}]
beginMacroMarkerStandalone [executedcontent] [] [{{footnote}}Second inner footnote{{/footnote}}]
beginMacroMarkerStandalone [footnote] [] [Second inner footnote]
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1-1]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1-1]]] [false]
onWord [4]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_1-1]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_1-1]]
endMacroMarkerStandalone [footnote] [] [Second inner footnote]
endMacroMarkerStandalone [executedcontent] [] [{{footnote}}Second inner footnote{{/footnote}}]
onEmptyLines [1]
beginMacroMarkerStandalone [footnote] [] [These are the footnotes:

{{putFootnotes/}}
]
beginFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_5]]
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_5]]] [false]
onWord [5]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_5]]] [false]
endFormat [SUPERSCRIPT] [[class]=[footnoteRef][id]=[x_footnote_ref_5]]
endMacroMarkerStandalone [footnote] [] [These are the footnotes:

{{putFootnotes/}}
]
beginMacroMarkerStandalone [putFootnotes] []
beginList [NUMBERED] [[class]=[footnotes]]
beginListItem
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1-2]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1-2]]
onWord [^]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1-2]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1-2]]
onSpace
onWord [content]
onSpace
onWord [1]
endListItem
beginListItem
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_2]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_2]]
onWord [^]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_2]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_2]]
onSpace
onWord [content]
onSpace
onWord [2]
endListItem
beginListItem
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1]]
onWord [^]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1]]
onSpace
onWord [Inner]
onSpace
onWord [footnote]
endListItem
beginListItem
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1-1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1-1]]
onWord [^]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_1-1]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_1-1]]
onSpace
onWord [Second]
onSpace
onWord [inner]
onSpace
onWord [footnote]
endListItem
beginListItem
beginLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_5]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_5]]
onWord [^]
endLink [Typed = [true] Type = [doc] Parameters = [[anchor] = [x_footnote_ref_5]]] [false] [[class]=[footnoteBackRef][id]=[x_footnote_5]]
onSpace
beginParagraph
onWord [These]
onSpace
onWord [are]
onSpace
onWord [the]
onSpace
onWord [footnotes]
onSpecialSymbol [:]
endParagraph
endListItem
endList [NUMBERED] [[class]=[footnotes]]
endMacroMarkerStandalone [putFootnotes] []
endDocument